作者:帥地 (本文來自作者投稿)
跟著西瓜兄弟學演演算法







老大:我簡單給你講下吧,你學過那麼多排序,估計一看就懂了。基數排序,是一種基數“桶”的排序,他的排序思路是這樣的:先以個位數的大小來對資料進行排序,接著以十位數的大小來多數進行排序,接著以百位數的大小……
排到最後,就是一組有序的元素了。不過,他在以某位數進行排序的時候,是採用“桶”來排序的,基本原理就是把具有相同個(十、百等)位數的數放進同一個桶裡。我直接給你個例子吧,保證你一看就懂。
例如我們現在要對這組元素來排序:

由於我們是以每個數的某位數來排序的,這位數的範圍是0-9,所以我們需要10個桶。

第一遍,先以個位數排序,把具有相同個位數的數放進桶裡,結果如下:

之後再按照從0號桶到9號桶的順序取出來,結果如下

個位數排序完成。
第二遍,以十位數來排,結果如下:

再取出來放回去:

十位數排序完成,最終的結果就是一組有序的元素。如果元素中有百位數的話,大不了就按照百位數再給他重覆排一遍。



老二:那我想問下,為啥要從個位數開始排序呢?可以直接從最高位開始排序嗎?如果從最高位開始排序的話,如果一個數最高位比另一個數大,那麼這個數就一定比另外一個數大了,不用在比較次高位了。這樣的話,不是可以排的更快嗎?

老大:腦子反應的挺快啊。是的,是可以以最高位來排序的,而且也像你說的,以最高位來排序的話,是可以減少資料之間比較的次數。但我們仍然不建議以最高位來排序,因為他有個致命的缺點。


老大:還是以剛才那個例子吧,我們一邊用最高位來排序,一邊來尋找這個致命的缺點。陣列如下(元素的順序改變了一些):

第一遍:最高位十位數排序,結果如下(有些沒用到的桶給省略了):

顯然,不在桶一個桶裡的數,他們的大小順序已經是已知的了,也就是說,右邊桶的數一定比左邊桶的數大,所有在接下來的個位數排序裡,我們只需要進行“各部分”單獨排序就可以了,每一小部分都類似於原問題的一個子問題,做的時候可以採用遞迴的形式來處理。

最後彙總,即可完成排序:

這種方法確實可以減少比較的次數,不過請大家註意,在每個小部分的排序中,我們也是需要10個桶來將他們進行排序,最後導致的結果就是,每個不同值的元素都會佔據一個“桶”,如果你有1000個元素,並且1000個元素都是不同值的話,那麼從最高位排序到最低位,需要1000個桶。
這樣子的話,空間花費不僅大,而且看起來有點背離基數排序最初的思想了(“背離”這個詞,個人感覺而已)。所以,我們一般採用從最低位到最高位的順序哦。

關於基數排序,還有以下幾個問題,你不妨也想一想?
1、基數排序是一種用空間換時間的排序演演算法,資料量越大,額外的空間就越大?
我的想法:我覺得基數排序並非是一種時間換空間的排序,也就是說,資料量越大,額外的空間並非就越大。因為在把元素放進桶的時候,是完全可以用指標指向這個元素的,也就是說,只有初始的那些桶才算是額外的空間。
2、居然額外空間不是限制基數排序速度的原因,那為啥基數排序沒有快速排序快呢?
基數的時間複雜度為O(n),不過他是忽略了常數項,即實際排序時間為kn(其中k是常數項),然而在實際排序的過程中,這個常數項k其實是很大的,這會很大程度影響實際的排序時間,而像快速排序雖然是nlogn,但它前面的常數項是相對比較小的,影響也相對比較小。
需要說明的是,基數排序也並非比快速排序慢,這得看具體情況,(不要被標題所影響哈)。而且,資料量越大的話,基數排序會越有優勢。
3、有人可能會問,說了這麼多,那到底是基數排序快還是快速排序快呢?
對於這樣的問題,我只能建議你,自己根據不同的場景,擼幾行程式碼,自己測試一下。
如果你問我,哪個排序在實際中用的更多,那麼,我選快速排序。
【本文作者】
帥地:一名熱愛程式設計的在校生,目前維護訂閱號「苦逼的碼農」,專註於寫於程式設計相關的文章