1. 程式人生 > >記數排序 & 桶排序 & 基數排序

記數排序 & 桶排序 & 基數排序

png enter 思想 line 似的 需要 max 數列 解決

為什麽要寫這樣滴一篇博客捏...因為一個新初一問了一道水題,結果就莫名其妙引起了戰鬥。

然後突然發現之前理解的桶排序並不是真正的桶排序,所以寫一篇來區別下這三個十分相似的排序辣。

老年菜兔的覺醒!!!

記數排序

記數排序是一種很快的排序算法,但是要很多的空間。

具體的操作:

技術分享

比如說給一個這樣的數列: 6 9 3 2 3 5

我萌需要一個數組 a[i] 表示 數列中 數值為 i 的有多少個

這樣 就可以 O(n) 處理出這個數組

  read(x);
  a[x]++;

比如辣個栗子的a數組是這樣滴

i 1 2 3 4 5 6 7 8 9
a[i] 0 1 2 0 1 1 0 0 1

然後這個數組有什麽用捏

可以發現,只需要枚舉 i (如栗子裏是 1≤i≤9 )

然後輸出 a[i] 個 i 後就是一個從小到大排序後的數列

for i=1 to 9 do (通常可以取數列中的最大數max,這裏取栗子的9)
  for j=1 to a[i] do
  write(i, );

這樣之後就會輸出 2 3 3 5 6 9

這就是記數排序(老年菜兔之前把計數排序誤以為是桶排序QAQ)

效率基本為 O(N) 但是有一個缺陷,就是當數列的值十分十分大的時候,數組就開不下了。

這個問題怎麽解決好捏,就是桶排序和基數排序辣!

桶排序

桶排序實際上是對計數排序的一些優化,他把時間又換回了一部分空間(計數排序用空間換時間)。

桶排序思想是什麽捏?

技術分享

繼續舉個栗子呀 6 9 3 2 3 5 (咦好熟悉)

首先我萌要定一個值 m 這個值可以任意定,但會影響到效率。

m是幹什麽用的?

不如這樣理解一下,計數排序實際上就是用了好多好多個桶 總共 max 個

而桶排序是用了 (max/m) 個桶 所以這個 m 的含義實際上是區間範圍。

計數排序是桶排序的一種特殊情況,就是 取 m=1的時候。

這時我萌需要一個數組 a[i,j]表示 第 i 個桶中的第j個元素的數值。

(通常不用數組而是鏈表,原因是可能有這樣的數據 如數列中全都是1-3範圍的 這時數組就開不下,如果n十分大)

嗯列個表吧

這裏我萌取 m=3 (就是舉個栗子)

桶中數據的範圍 1~3 4~6 7~9
相應的i(也就是第幾個桶) 1 2 3
桶內的元素 3,2,3 6.5 9

這時發現什麽捏...每一個桶裏的元素是無序的。

所以對每一個桶都做一個其他的排序,如快排。

然後排序後再把這些桶合並起來就好啦

誒???每一個桶?辣麽效率豈不是很低。

答案是否定的,相反,桶排序效率通常比快排快。

快排的平均效率為O(n log n) 而桶排捏是 O(max/m *m log m) 即 O(max log M) 假設max=n=1000000(1百萬)

快排的計算量約 23000000(2300萬) 而 桶排序如果取M=2500(既省了一點空間,又有很高的時間效率) 的計算量約 12000000(1200萬)

可見桶排序效率也比較高。

而且桶排序每個桶的排序算法還可以換為其他的不一定要快排。

桶排序的應用似乎不多,而似乎很多人搞混了基數排序與桶排序。

相比之下把基數排序誤認為是桶排序的人會更多的樣子。

所以基數排序的應用應該更廣。

基數排序

基數排序的方法更是神奇,他用到了計數排序的思想。

基數排序的操作我還是要舉個栗子...不過圖就不放了QAQ不然水的成分有點大

如:543 123 756 666 841 322 10 799 69 (終於換了個栗子,因為上一次栗子次掉了)

基數排序的操作是這樣的。

最低位(個位)為一個關鍵字,次低位是一個關鍵字...以此類推。

我萌先對最低位為關鍵字做一次計數排序。

如果依舊用桶來比喻的話,因為一個位數上只會有0-9 這些數字。

所以就是10個桶

列個表吧

0 1 2 3 4 5 6 7 8 9

第1次操作後

桶裏的元素

10 841 322 543,123 756,666 799,69

然後第一次操作後再合並起來就是這樣的數列 (註意每一個桶內是無序的,都是按原來數列的位置)

10 841 322 543 123 756 666 799 69

還是一個無序的數列,接著對次低位為關鍵字做記數排序

0 1 2 3 4 5 6 7 8 9

第2次操作後

桶裏的元素

10 322,123 841,543 756 666,69 799

然後第二次操作後再合並起來就是這樣的數列(註意每一個桶內依舊是無序的,都是按第一次操作後的數列的位置)

10 322 123 841 543 756 666 69 799

然後就第三低位為關鍵字做記數排序

0 1 2 3 4 5 6 7 8 9

第2次操作後

桶裏的元素

010,069 123 322 543 666 756,799 841

然後合並

10 69 123 322 543 666 756 799 841

這時排序結束,數列有序了。

是不是很神奇捏?

為什麽要對每一位都做一次計數排序?

實際上就是改變位置。比如如果出現了 123 124 這樣的元素,在原來數列是這樣的 124 123

辣麽對最低位進行計數排序就可以變成 123 124 從而改變了位置。

好了,辣基數排序的效率?

設最大值有 d 位

約O(d*n) 的效率

而d是十分小的,相比桶排序,雖然效率變低了一點,但適用於一些數值十分大的數據。

再擴充一點基排

實際上,這裏使用了10個桶,辣麽可不可以多用些桶捏?當然可以

我萌可以使用100個桶,講最低位和次低位看成一個整體 為一個關鍵字,比如 5678 此時 以78 為一個關鍵字 56為另一個關鍵字。

然後操作是一樣的但是卻只有 d/2個關鍵字了,從而效率又快了,但空間變多了,變成了100個桶。

以此類推,還有1000 10000 ...個桶。辣如果不是整10個桶行不行,當然行,這樣的話需要把10進制數看為其他進制的數來做計數排序。具體就不細講啦~

好啦~講完啦,總結一下吧,總體來說,三個排序都是用到了計數排序的思想。

桶排序效率高,但數值過大還是無法使用,而基數排序不僅效率高了很多,而且適用數值大的數據。

老年菜兔的講解結束啦~撒花~

記數排序 & 桶排序 & 基數排序