思想
桶排序,也是爲了解決計數排序計數數組大小設置的問題。桶排序,就是把待排序數據分爲不同的區間,然後區間內進行排序,最後即可完成排序。
就有點像,成績會有一個區間,比如100-90, 90-80這樣,每個區間就是一個桶,然後對桶內元素進行排序。最後取出來,即完成排序。
從上面分析可以看出,我們對區間排序的時候,最好每個區間(桶)中數據是均勻的。
至於如何對桶內元素進行排序?這個是一個困惑,網上很多給的實例,是直接調用 api 的排序函數。
維基百科上,是對桶內數據採用插入排序的方法。
我個人偏向於第二種。
第一種有點投機取巧,雖然Java中的排序函數,會根據數據量的大小選用不同的排序函數,因爲不同的數據量,不同的排序函數的時間效率還是有點差別的。java中的排序函數應該會根據數據量大小,調用相對高效的排序函數。
這裏還得知道,在數據量較小的情況下,插入排序比快排和歸併要高效。因爲桶分數據,相對假設每個桶的數據都比較少,所以個人偏向桶內排序採用插入排序。
實現
貼出維基百科上的代碼
private int indexFor(int a, int min, int step) {
return (a - min) / step;
}
public void bucketSort(int[] arr) {
int max = arr[0], min = arr[0];
for (int a : arr) {
if (max < a)
max = a;
if (min > a)
min = a;
}
// 該值也可根據實際情況選擇
int bucketNum = max / 10 - min / 10 + 1;
List buckList = new ArrayList<List<Integer>>();
// create bucket
for (int i = 1; i <= bucketNum; i++) {
buckList.add(new ArrayList<Integer>());
}
// push into the bucket
for (int i = 0; i < arr.length; i++) {
int index = indexFor(arr[i], min, 10);
((ArrayList<Integer>) buckList.get(index)).add(arr[i]);
}
ArrayList<Integer> bucket = null;
int index = 0;
for (int i = 0; i < bucketNum; i++) {
bucket = (ArrayList<Integer>) buckList.get(i);
insertSort(bucket);
for (int k : bucket) {
arr[index++] = k;
}
}
}
// 把桶內元素插入排序
private void insertSort(List<Integer> bucket) {
for (int i = 1; i < bucket.size(); i++) {
int temp = bucket.get(i);
int j = i - 1;
for (; j >= 0 && bucket.get(j) > temp; j--) {
bucket.set(j + 1, bucket.get(j));
}
bucket.set(j + 1, temp);
}
}
需要注意的是,桶的數據結構,是採用arraylist接arraylist。
下圖中是鏈表形式,所以我塗改了,應該是arraylist而不是鏈表。
複雜度
複雜度分析的話,主要是取決於每個桶中的時間複雜度。
如果桶爲很多,每個桶中只有一個數據,那麼其實就是計數排序。