桶排序的思想近乎完全的分治思想。桶排序是鴿巢排序的一種概括結果。html
桶排序 (Bucket sort)或所謂的箱排序,是一個非比較排序算法,是基於映射函數實現的。工做的原理是將數組分到有限數量的桶子裏。每一個桶子再個別排序(有可能再使用別的排序算法或是以遞歸方式繼續使用桶排序進行排序)。桶排序是鴿巢排序的一種概括結果。當要被排序的數組內的數值是均勻分配的時候,桶排序使用線性時間(Θ(n))。java
桶排序是計數排序的升級版【能夠實數】。它利用了函數的映射關係,高效與否的關鍵就在於這個映射函數的肯定。爲了使桶排序更加高效,咱們須要作到這兩點:算法
同時,對於桶中元素的排序,選擇何種比較排序算法對於性能的影響相當重要。數組
元素分佈在桶中:數據結構
而後,元素在每一個桶中排序:函數
Linked List Array index = Value * NUMBER_OF_ELEMENTS / (MAXIMUM_ARRAY_VALUE +1) = (value * 30)/1000post
MAXIMUM_ARRAY_VALUE 加1是爲了保證最大元素能夠存到數組最後一個位置,即arr.length - 1處。性能
對於N個待排數據,M個桶,平均每一個桶[N/M]個數據的桶排序平均時間複雜度爲:O(N)+O(M*(N/M)*log(N/M))=O(N+N*(logN-logM))=O(N+N*logN-N*logM),桶排序的平均時間複雜度爲線性的O(N+C),其中C=N*(logN-logM)。優化
當M=N時,即極限狀況下每一個桶只有一個數據時。桶排序的最好效率可以達到O(N)。動畫
當M=1時,即極限狀況下只有一個桶時。桶排序的最壞效率達到O(N*logN)。
桶排序的空間複雜度 爲O(N+M),若是輸入數據很是龐大,而桶的數量也很是多,則空間代價較大。
桶排序是穩定的算法。【桶排序能夠是穩定的。這取決於咱們對每一個桶中的元素採起何種排序方法,好比桶內元素的排序使用快速排序,那麼桶排序就是不穩定的;若是使用的是插入排序,桶排序就是穩定的。】
桶排序也不能很好地應對元素值跨度很大的數組。好比[3, 2, 1, 0 ,4, 8, 6, 999],按照上面的映射規則,999會放入一個桶中,剩下全部元素都放入同一個桶中,在各個桶中元素分佈極不均勻,這就失去了桶排序的意義。
桶排序和計數排序有個共同的缺點:耗費大量空間。
再細看桶排序,其實計數排序能夠看做是桶排序的一種特例,計數排序至關於將全部相同的元素放入同一個桶中,而桶排序能夠將必定範圍內的元素都放入同一個桶中;另外,桶排序的數據結構很像基於拉鍊法的散列表,只是定義的映射函數不一樣。桶排序的映射函數將較大值映射成較大的索引,這二者是呈正相關的。而散列表的映射函數獲得的哈希值是隨意的。
import java.util.ArrayList; import java.util.Arrays; import java.util.*; public class BucketSort{
// 通常建立的桶數量等於原始數列的元素數量,除了最後一個桶只包含數列最大值,前面各個桶的區間按照比例肯定。【OR 桶數量等於原始數列的元素數量+1,除了第一個桶只包含數列最小值,最後一個桶只包含數列最大值,中間各個桶的區間按照比例肯定。】
// 區間跨度 = (最大值-最小值)/ (桶的數量 - 1)
// 定位元素屬於第幾個桶,是按照比例來定位:(array[i] - min) * (bucketNum-1) / (max - min)
public static double[] bucketSort(double[] array, int bucketNum){ //1.獲得數列的最大值和最小值,並算出差值d double max = array[0]; double min = array[0]; for(int i=1; i<array.length; i++) { if(array[i] > max) { max = array[i]; } if(array[i] < min) { min = array[i]; } } // 下面的運行慢 // double max = Arrays.stream(array).max().getAsDouble(); // double min = Arrays.stream(array).min().getAsDouble(); double d = max - min; //2.初始化桶 //int bucketNum = array.length; ArrayList<LinkedList<Double>> bucketList = new ArrayList<LinkedList<Double>>(bucketNum); for(int i = 0; i < bucketNum; i++){ bucketList.add(new LinkedList<Double>()); } //3.遍歷原始數組,將每一個元素放入桶中 for(int i = 0; i < array.length; i++){ int num = (int)((array[i] - min) * (bucketNum-1) / d); bucketList.get(num).add(array[i]); } //4.對每一個通內部進行排序 for(int i = 0; i < bucketList.size(); i++){ //JDK底層採用了歸併排序或歸併的優化版本 Collections.sort(bucketList.get(i)); } //5.輸出所有元素 double[] sortedArray = new double[array.length]; int index = 0; for(LinkedList<Double> list : bucketList){ for(double element : list){ sortedArray[index] = element; index++; } } return sortedArray; } public static void main(String[] args) { double[] array = new double[] {4.12,6.421,0.0023,3.0,2.123,8.122,4.12, 10.09}; double[] sortedArray = bucketSort(array,3); System.out.println(Arrays.toString(sortedArray)); } }