基於桶的基數排序
推出一個新系列,《看圖輕鬆理解資料結構和演算法》,主要使用圖片來描述常見的資料結構和演算法,輕鬆閱讀並理解掌握。本系列包括各種堆、各種佇列、各種列表、各種樹、各種圖、各種排序等等幾十篇的樣子。
基數排序
基數排序(Radix Sort)演算法是一種非比較的排序演算法,早在 1887 年 Herman Hollerith 就已經在打孔卡片製表機中使用該演算法。一般多用於對整數的排序,但由於整數與某些字元能互相轉換,所以它也能夠用於字串的排序。簡單來說,基數排序演算法就是將整數或字串切分成不同的數字或字元,然後按對應位置的數或字元分別進行比較。
穩定性
基數排序具備穩定性,即能保證相同值元素之間的相對順序在排序前後一致。基於計數排序的方式主要是通過對計數陣列進行字首和運算,外加通過額外的輔助陣列,最後逆序迴圈將待排序陣列中的所有元素放置到輔助陣列中,以達到穩定性效果。而基於桶的方式則是通過在每個桶中控制順序,從而達到穩定性效果。
時間複雜度
基數排序的時間複雜度為Ο(w(n+k)),其中n為待排序陣列長度;k為關鍵字的取值範圍,等於進位制數,比如十進位制則k=10;w為待排序陣列元素最大的字長,比如最大字長元素為 358
,則字長為3。
當k確定後,時間複雜度其實就是O(wn),但有時還需要考慮字長w,不能簡單將其認定為常數。假如取基數為B(即B進位制),待排序集合最大元素為N,k為大於 的最小整數。所以並不是說基數排序就一定完勝最好的比較排序(O(n * log n)),實際過程中還跟所取的基和待排序集合具體的情況相關。
排序方式
基數排序可以採用最高有效數位(MSD)和最低有效數位(LSD)兩種方式,其中LSD的排序方式由鍵值的最右邊開始,而MSD則相反,由鍵值的最左邊開始。
在演算法過程中,對於LSD,對某個有效數位分配後需要執行一次合併,然後再對下一位分配;而對於MSD,對某個有效數位分配後不執行合併,它將繼續對相同高位的元素繼續進行分配,直到無法繼續分配時執行合併操作。
基於桶實現
基於桶方式是指使用桶作為輔助工具,過程中迴圈每個有效數位將元素分配到對應的桶中,從而實現基數排序。
基於桶方式的基數排序的操作步驟如下:
- 確定桶的數量,由進位制數確定,比如十進位制則桶的數量為10,分別代表0到9,並且每個桶內的結構為佇列。
- 從最低有效位到最高有效位,針對每個有效位執行步驟3到步驟5。
- 按順序遍歷待排序陣列,根據當前有效位將它們分配到對應桶的佇列中。
- 按桶編號順序進行遍歷,將每個桶中佇列按順序收集到原陣列中。
- 選擇下一個有效位執行步驟2到步驟4,直到所有有效位處理完得到的結果即是最終的結果。
同樣是對前面的8位小學生的語數英總成績進行基於桶方式的基數排序操作。一共有8個學生,所以待排序陣列長度為8。而且因為使用十進位制,所以桶的索引範圍是0-9。此外每個桶對應建立一個佇列,這裡假設佇列長度為5,長度也可以為待排序陣列長度,但實際中更多使用動態擴充套件策略。

第一階段:針對個位數將元素放到對應的桶中。
待排序陣列的第一個元素的健值為198,放到編號8的桶中。

第二個元素的健值為248,放到編號為8的桶中。

第三個元素的健值為98,放到編號為8的桶中。

第四個元素的健值為247,放到編號為7的桶中。

類似地,將剩下的元素都放到對應桶中的佇列,可以看到每個桶中的佇列維護了順序性。

接著按桶順序將桶中佇列輸出到原陣列中,先輸出編號為0的桶。

接著輸出編號為7的桶。

再輸出編號為8的桶。

最後輸出編號為9的桶。

第二階段:針對十位數將元素放到對應的桶中。
待排序陣列的第一個元素的健值為80,放到編號8的桶中。

第一個元素的健值為247,放到編號4的桶中。

將剩下的元素都放到對應桶中的佇列。

將編號為4的桶的佇列輸出到原陣列中。

將編號為8的桶的佇列輸出到原陣列中。

將編號為9的桶的佇列輸出到原陣列中。

第三階段:針對百位數將元素放到對應的桶中。
第一個元素的健值為247,放到編號2的桶中。

第二個元素的健值為247,放到編號2的桶中。

將剩下的元素都放到對應桶中的佇列。

將編號為0的桶的佇列輸出到原陣列中。

將編號為1的桶的佇列輸出到原陣列中。

將編號為2的桶的佇列輸出到原陣列中。

至此,以上完成整個排序過程。
-------------推薦閱讀------------
我的開源專案彙總(機器&深度學習、NLP、網路IO、AIML、mysql協議、chatbot)
跟我交流,向我提問:

歡迎關注:
