計算與資料結構篇 排序 桶排序

2021-10-01 21:05:55 字數 2461 閱讀 4201

排序是乙個特別常見的問題,也是演算法與資料結構中繞不開的話題,有次去小公尺,面試官問我這樣乙個場景,每週四10點是小公尺開放日,在一段時間內,會湧進2kw的資料流,怎麼排序,當時會有訂單狀態?

桶排序、計數排序、基數排序以上這三種排序演算法是適用於某個特別的場景。

核心思想是將要排序的資料分到幾個有序的桶裡,每個桶裡的資料再單獨進行排序。桶內排完序之後,再把每個桶裡的資料按照順序依次取出,組成的序列就是有序的了。

如果要排序的資料有 n 個,我們把它們均勻地劃分到 m 個桶內,每個桶裡就有 k=n/m 個元素。每個桶內部使用快速排序,時間複雜度為 o(k * logk)。m 個桶排序的時間複雜度就是 o(m * k * logk),因為 k=n/m,所以整個桶排序的時間複雜度就是 o(n*log(n/m))。當桶的個數 m 接近資料個數 n 時,log(n/m) 就是乙個非常小的常量,這個時候桶排序的時間複雜度接近 o(n)。

桶排序對特殊場景是有要求的,

比如說我們有 10gb 的訂單資料,我們希望按訂單金額(假設金額都是正整數)進行排序,但是我們的記憶體有限,只有幾百 mb,沒辦法一次性把 10gb 的資料都載入到記憶體中。這個時候該怎麼辦呢?

我們可以先掃瞄一遍檔案,看訂單金額所處的資料範圍。假設經過掃瞄之後我們得到,訂單金額最小是 1 元,最大是 10 萬元。我們將所有訂單根據金額劃分到 100 個桶裡,第乙個桶我們儲存金額在 1 元到 1000 元之內的訂單,第二桶儲存金額在 1001 元到 2000 元之內的訂單,以此類推。每乙個桶對應乙個檔案,並且按照金額範圍的大小順序編號命名(00,01,02…99)。

不過,你可能也發現了,訂單按照金額在 1 元到 10 萬元之間並不一定是均勻分布的 ,所以 10gb 訂單資料是無法均勻地被劃分到 100 個檔案中的。有可能某個金額區間的資料特別多,劃分之後對應的檔案就會很大,沒法一次性讀入記憶體。這又該怎麼辦呢?

針對這些劃分之後還是比較大的檔案,我們可以繼續劃分,比如,訂單金額在 1 元到 1000 元之間的比較多,我們就將這個區間繼續劃分為 10 個小區間,1 元到 100 元,101 元到 200 元,201 元到 300 元…901 元到 1000 元。如果劃分之後,101 元到 200 元之間的訂單還是太多,無法一次性讀入記憶體,那就繼續再劃分,直到所有的檔案都能讀入記憶體為止。

/**

* 第一種桶排序的辦法,每個桶儲存相同值的資料

**/function

bucketsort

($nonsortarray

)//資料出桶

$sortarray

=array()

;foreach

($bucket

as$k

=>$v)

}return

$sortarray

;}

計數排序其實是桶排序的一種特殊情況。當要排序的 n 個資料,所處的範圍並不大的時候,比如最大值是 k,我們就可以把資料劃分成 k 個桶。每個桶內的資料值都是相同的,省掉了桶內排序的時間。

我們都經歷過高考,高考查分數系統你還記得嗎?我們查分數的時候,系統會顯示我們的成績以及所在省的排名。如果你所在的省有 50 萬考生,如何通過成績快速排序得出名次呢?

考生的滿分是 900 分,最小是 0 分,這個資料的範圍很小,所以我們可以分成 901 個桶,對應分數從 0 分到 900 分。根據考生的成績,我們將這 50 萬考生劃分到這 901 個桶裡。桶內的資料都是分數相同的考生,所以並不需要再進行排序。我們只需要依次掃瞄每個桶,將桶內的考生依次輸出到乙個陣列中,就實現了 50 萬考生的排序。因為只涉及掃瞄遍歷操作,所以時間複雜度是 o(n)。

考生的滿分是 900 分,最小是 0 分,這個資料的範圍很小,所以我們可以分成 901 個桶,對應分數從 0 分到 900 分。根據考生的成績,我們將這 50 萬考生劃分到這 901 個桶裡。桶內的資料都是分數相同的考生,所以並不需要再進行排序。我們只需要依次掃瞄每個桶,將桶內的考生依次輸出到乙個陣列中,就實現了 50 萬考生的排序。因為只涉及掃瞄遍歷操作,所以時間複雜度是 o(n)。

function

countingsort

($arr

)//初始化用來計數的陣列

for($i=

0;$i<=

$max;$i

++)//對計數陣列中鍵值等於$arr[$i]的加1

for($i=

0;$i<

$size;$i

++)//相鄰的兩個值相加

for($i=

1;$i<=

$max;$i

++)//鍵與值翻轉

for($i=

$size-1

;$i>=0;

$i--

)//按照順序排列

$result

=array()

;for($i

=1;$i

<=

$size;$i

++)return

$result

;}

資料結構與演算法 桶排序

與基數排序法一樣,桶排序也是一種排序的思想。待排資料的值必須在乙個範圍內,然後把這個值域空間劃分為若干區塊,每乙個對應乙個桶,把待排陣列放入到合適的桶中,再對桶內的資料採用任意一種方式排序。整個時間複雜度分為兩部分,第一部分是入桶,為on,第二部分則是所有桶內排序的時間。演算法導論 中證明了這個整體...

資料結構與演算法 桶排序

桶排序可以看成是計數排序的公升級版,它將要排的資料分到多個有序的桶裡,每個桶裡的資料再單獨排序,再把每個桶的資料依次取出,即可完成排序。我們拿一組計數排序啃不掉的資料 500,6123,1700,10,9999 來舉例。第一步,我們建立 10 個桶,分別來裝 0 1000 1000 2000 200...

資料結構 基數排序(桶排序)

基數排序和計數排序都屬於 非比較排序 有關計數排序可檢視 基數排序介紹 基數排序 radix sort 屬於 分配式排序 distribution sort 又稱 桶子法 bucket sort 或bin sort,顧名思義,它是透過鍵值的部份資訊,將要排序的元素分配至某些 桶 中,藉以達到排序的作...