桶排序算是計數排序的一種改進和推廣,可是網上有許多資料把計數排序和桶排序混爲一談。其實桶排序要比計數排序複雜許多。 算法
對桶排序的分析和解釋借鑑這位兄弟的文章(有改動):http://hxraid.iteye.com/blog/647759
桶排序的基本思想: 數組
假設有一組長度爲N的待排關鍵字序列K[1….n]。首先將這個序列劃分紅M個的子區間(桶) 。而後基於某種映射函數 ,將待排序列的關鍵字k映射到第i個桶中(即桶數組B的下標 i) ,那麼該關鍵字k就做爲B[i]中的元素(每一個桶B[i]都是一組大小爲N/M的序列)。接着對每一個桶B[i]中的全部元素進行比較排序(可使用快排)。而後依次枚舉輸出B[0]….B[M]中的所有內容便是一個有序序列。bindex=f(key) 其中,bindex 爲桶數組B的下標(即第bindex個桶), k爲待排序列的關鍵字。桶排序之因此可以高效,其關鍵在於這個映射函數,它必須作到:若是關鍵字k1 函數
舉個栗子:
性能
假如待排序列K= {4九、 38 、 3五、 97 、 7六、 73 、 2七、 49 }。這些數據所有在1—100之間。所以咱們定製10個桶,而後肯定映射函數f(k)=k/10。則第一個關鍵字49將定位到第4個桶中(49/10=4)。依次將全部關鍵字所有堆入桶中,並在每一個非空的桶中進行快速排序後獲得如圖所示。只要順序輸出每一個B[i]中的數據就能夠獲得有序序列了。 code
桶排序分析: orm
桶排序利用函數的映射關係,減小了幾乎全部的比較工做。實際上,桶排序的f(k)值的計算,其做用就至關於快排中劃分,希爾排序中的子序列,歸併排序中的子問題,已經把大量數據分割成了基本有序的數據塊(桶)。而後只須要對桶中的少許數據作先進的比較排序便可。blog
對N個關鍵字進行桶排序的時間複雜度分爲兩個部分:排序
(1) 循環計算每一個關鍵字的桶映射函數,這個時間複雜度是O(N)。索引
(2) 利用先進的比較排序算法對每一個桶內的全部數據進行排序,其時間複雜度爲 ∑ O(Ni*logNi) 。其中Ni 爲第i個桶的數據量。圖片
很顯然,第(2)部分是桶排序性能好壞的決定因素。儘可能減小桶內數據的數量是提升效率的惟一辦法(由於基於比較排序的最好平均時間複雜度只能達到O(N*logN)了)。所以,咱們須要儘可能作到下面兩點:
(1) 映射函數f(k)可以將N個數據平均的分配到M個桶中,這樣每一個桶就有[N/M]個數據量。
(2) 儘可能的增大桶的數量。極限狀況下每一個桶只能獲得一個數據,這樣就徹底避開了桶內數據的「比較」排序操做。固然,作到這一點很不容易,數據量巨大的狀況下,f(k)函數會使得桶集合的數量巨大,空間浪費嚴重。這就是一個時間代價和空間代價的權衡問題了。
對於N個待排數據,M個桶,平均每一個桶[N/M]個數據的桶排序平均時間複雜度爲:
O(N)+O(M(N/M)log(N/M))=O(N+N(logN-logM))=O(N+NlogN-N*logM)
當N=M時,即極限狀況下每一個桶只有一個數據時。桶排序的最好效率可以達到O(N)。
總結: 桶排序的平均時間複雜度爲線性的O(N+C),其中C=N*(logN-logM)。若是相對於一樣的N,桶數量M越大,其效率越高,最好的時間複雜度達到O(N)。 固然桶排序的空間複雜度 爲O(N+M),若是輸入數據很是龐大,而桶的數量也很是多,則空間代價無疑是昂貴的。此外,桶排序是穩定的。
實現代碼:
public class BucketSort { public static void bucketSort(int[] arr) { if(arr == null & arr.length == 0) return ; int bucketNums = 10; //這裏默認爲10,規定待排數[0,100) List> buckets = new ArrayList>(); //桶的索引 for(int i=0; i) { buckets.add(new LinkedList()); //用鏈表比較合適 } //劃分桶 for(int i=0; i) { buckets.get(f(arr[i])).add(arr[i]); } //對每一個桶進行排序 for(int i=0; i) { if(!buckets.get(i).isEmpty()) { Collections.sort(buckets.get(i)); //對每一個桶進行快排 } } //還原排好序的數組 int k = 0; for(List bucket : buckets) { for(int ele : bucket) { arr[k++] = ele; } } } /** * 映射函數 * @param x * @return */ public static int f(int x) { return x / 10; } }