桶排序的簡單理解
詳細描述
桶排序的工作原理是,將序列中的元素分配到有限的桶里,每個桶再分別進行排序(使用別的排序演算法或者遞歸使用桶排序),最終合併成結果序列。
桶排序詳細的執行步驟如下:
- 找出序列中最小的元素和最大的元素,並計算得到差值範圍和映射範圍,確定桶的數量;
- 遍歷整個序列,將每一個元素移動到對應的桶中;
- 對每一個桶中的元素進行排序,直到所有的桶中元素都有序;
- 合併每一個桶中的元素成為有序序列。
演算法圖解
問題解疑
桶排序的關鍵是什麼?
桶排序過程中存在兩個關鍵環節:元素到桶的映射規則、排序演算法選擇。
對於映射規則,如果規則設計過於模糊、寬泛,可能所有元素都映射到同一個桶,導致桶排序往比較類排序演算法演變;如果規則設計過於嚴苛,可能每一個桶只分配到一個元素,導致桶排序往計數排序方式演變。
對於桶中元素的排序,可以繼續使用桶排序或者其他排序演算法,最終桶排序的複雜度和穩定性,都根據排序演算法的選擇有所不同。
桶排序的適用於什麼場景?
最好時間複雜度的場景是:序列中的元素值範圍越小越好,比如對範圍只有 10 的序列做排序,申請 10 個桶就能實現遍歷一次序列完成排序。
最好空間複雜度的場景是:序列中的元素值均勻分布,最終分配到每一個桶的元素數量都相差不大,這樣可以避免數據傾斜的問題。
程式碼實現
package cn.fatedeity.algorithm.sort;
import java.util.ArrayList;
import java.util.List;
/**
* 桶排序演算法
*/
public class BucketSort {
private static void swap(List<Integer> numbers, int src, int target) {
int temp = numbers.get(src);
numbers.set(src, numbers.get(target));
numbers.set(target, temp);
}
private static void insertSort(List<Integer> numbers) {
for (int i = 1; i < numbers.size(); i++) {
for (int j = i; j > 0; j--) {
if (numbers.get(j - 1) <= numbers.get(j)) {
break;
}
swap(numbers, j, j - 1);
}
}
}
public static int[] sort(int[] numbers) {
if (numbers.length == 0) {
return numbers;
}
int min = numbers[0], max = numbers[0];
for (int number : numbers) {
if (number < min) {
min = number;
} else if (number > max) {
max = number;
}
}
// 以 10 為步長
int bucketNum = (max - min) / 10 + 1;
List<List<Integer>> bucketList = new ArrayList<>();
for (int i = 0; i < bucketNum; i++) {
bucketList.add(new ArrayList<>());
}
// 將元素分配到桶中
for (int number : numbers) {
int index = (number - min) / 10;
List<Integer> bucket = bucketList.get(index);
bucket.add(number);
}
int index = 0;
for (int i = 0; i < bucketNum; i++) {
List<Integer> bucket = bucketList.get(i);
insertSort(bucket);
for (int number : bucket) {
numbers[index++] = number;
}
}
return numbers;
}
}