桶排序及其应用
桶排序(Bucket Sort)有時也稱為盒子排序(Bin Sort),來源于郵局使用的盒子信件分發方法。桶排序的有效性需假定輸入數據是由一個完全隨機過程產生,即要求桶排序的輸入數據呈均勻分布,例如,輸入數據隨機均勻分布在區間[0, 1)。
桶排序思想如下:
1)把區間[0, 1)分解為n個大小相等的桶;
2)將n個輸入數據按照其取值不同分配到n個桶里面;
3)對每個桶里面的數據進行排序;
4)然后將桶里面的數據按順序收集。
桶排序的偽代碼程序如下:
輸入數組:[1..n],對任意i,我們有0≤A[i]<1
輔助數組:B[0..n-1]個鏈表,初始狀態均為空
BUCKET-SORT(A, n):
For i=1 to n do
???????? 將數據A[i]插入鏈表B[floor(n×A[i])]里
For i=0 to n-1 do
???????? 對鏈表B[i]里面的數據進行插入排序
將鏈表B[0]、B[1]、...、B[n-1]首尾相連鏈接起來
注意:上面對每個桶里面的元素使用平方級的插入排序算法,一個原因是在我們假定輸入元素是均勻分布后,分配到任意一個特定桶里面的元素個數不會太多(否則就不均勻了,發生了聚集),因此插入排序的復雜性可以不用計較。
通過分析可以知道,桶排序是一個線性排序算法。
?
==============轉載的分割線===============
=====http://hxraid.javaeye.com/blog/649831#comments=====
(有修改)
桶排序在海量數據中的應用
一年的全國高考考生人數為500 萬,分數使用標準分,最低100 ,最高900 ,沒有小數,你把這500 萬元素的數組排個序。
分析:對500W數據排序,如果基于比較的先進排序,平均比較次數為O(5000000*log5000000)≈1.112億。但是我們發現,這些數據都有特殊的條件:? 100=<score<=900。那么我們就可以考慮桶排序這樣一個“投機取巧”的辦法、讓其在毫秒級別就完成500萬排序。
方法:創建801(900-100)個桶。將每個考生的分數丟進f(score)=score-100的桶中。這個過程從頭到尾遍歷一遍數據只需要500W次。然后根據桶號大小依次將桶中數值輸出,即可以得到一個有序的序列。而且可以很容易的得到100分有***人,501分有***人。
實際上,桶排序對數據的條件有特殊要求,如果上面的分數不是從100-900,而是從0-2億,那么分配2億個桶顯然是不可能的。所以桶排序有其局限性,適合元素值集合并不大的情況。
?
題目:在一個文件中有 10G 個整數,亂序排列,要求找出中位數。內存限制為 2G。只寫出思路即可(內存限制為 2G的意思就是,可以使用2G的空間來運行程序,而不考慮這臺機器上的其他軟件的占用內存)。
關于中位數:數據排序后,位置在最中間的數值。即將數據分成兩部分,一部分大于該數值,一部分小于該數值。中位數的位置:當樣本數為奇數時,中位數=(N+1)/2 ; 當樣本數為偶數時,中位數為N/2與1+N/2的均值(那么10G個數的中位數,就第5G大的數與第5G+1大的數的均值了)。
分析: 既然要找中位數,很簡單就是排序的想法。那么基于字節的桶排序是一個可行的方法。
思想:將整型的每1byte作為一個關鍵字,也就是說一個整形可以拆成4個keys,而且最高位的keys越大,整數越大。如果高位keys相同,則比較次高位的keys。整個比較過程類似于字符串的字典序。
?
第一步:把10G整數每2G讀入一次內存,然后一次遍歷這536,870,912即(1024*1024*1024)*2 /4個數據。每個數據用位運算">>"取出最高8位(31-24)。這8bits(0-255)最多表示255個桶,那么可以根據8bit的值來確定丟入第幾個桶。最后把每個桶寫入一個磁盤文件中,同時在內存中統計每個桶內數據的數量,自然這個數量只需要255個整形空間即可。
代價:(1) 10G數據依次讀入內存的IO代價(這個是無法避免的,CPU不能直接在磁盤上運算)。(2)在內存中遍歷536,870,912個數據,這是一個O(n)的線性時間復雜度。(3)把255個桶寫會到255個磁盤文件空間中,這個代價是額外的,也就是多付出一倍的10G數據轉移的時間。
?
?
?
第三步:繼續以內存中的整數的次高8bit進行桶排序(23-16)。過程和第一步相同,也是255個桶。
第四步:一直下去,直到最低字節(7-0bit)的桶排序結束。我相信這個時候完全可以在內存中使用一次快排就可以了。
注意,變態的情況下,這個需要讀入的第128號文件仍然大于2G,那么整個讀入仍然可以按照第一步分批來進行讀取。第二步:根據內存中255個桶內的數量,計算中位數在第幾個桶中。很顯然,2,684,354,560個數中位數是第1,342,177,280個。假設前127個桶的數據量相加,發現少于1,342,177,280,把第128個桶數據量加上,大于1,342,177,280。說明,中位數必在磁盤的第128個桶中。而且在這個桶的第1,342,177,280-N(0-127)個數位上。N(0-127)表示前127個桶的數據量之和。然后把第128個文件中的整數讀入內存。(平均而言,每個文件的大小估計在10G/128=80M左右,當然也不一定,但是超過2G的可能性很小)。
?
整個過程的時間復雜度在O(n)的線性級別上(沒有任何循環嵌套)。但主要時間消耗在第一步的第二次內存-磁盤數據交換上,即10G數據分255個文件寫回磁盤上。一般而言,如果第二步過后,內存可以容納下存在中位數的某一個文件的話,直接快排就可以了。
?
?
轉載于:https://www.cnblogs.com/android-html5/archive/2010/05/24/2534040.html
總結
- 上一篇: 基于粒子滤波的物体跟踪
- 下一篇: 《dojo 边学边用》(01), 初识d