1. 程式人生 > >八大排序演算法—16張圖搞懂基數排序

八大排序演算法—16張圖搞懂基數排序

>原創公眾號:bigsai 轉載需聯絡筆者 ## 前言 在排序演算法中,大家可能對桶排序、計數排序、基數排序不太瞭解,不太清楚其演算法的思想和流程,也可能看過會過但是很快就忘記了,但是不要緊,幸運的是你看到了本篇文章。本文將通俗易懂的給你講解基數排序。 基數排序,是一種原理簡單,但實現複雜的排序。很多人在學習基數排序的時候可能會遇到以下兩種情況而淺嘗輒止: - 一看原理,這麼簡單,懂了懂了(順便溜了) - 再一看程式碼,這啥啥啥啊?這些的肯定有問題(不看溜了) ![image-20201113205712629](https://bigsai.oss-cn-shanghai.aliyuncs.com/img/image-20201113205712629.png) 要想深入理解基數排序,必須搞懂基數排序各種形式(數字型別、等長字元型別、不等長字元)各自實現方法,瞭解其中的聯絡和區別,並且也要掌握空間優化的方法(非二維陣列而僅用一維陣列)。下面跟著我詳細學習基數排序吧! ## 基數排序原理 首先百度百科看看基數排序的定義: > 基數排序(radix sort)屬於“分配式排序”(distribution sort),又稱“桶子法”(bucket sort)或bin sort,顧名思義,它是透過鍵值的部份資訊,將要排序的元素分配至某些“桶”中,藉以達到排序的作用,基數排序法是屬於穩定性的排序,基數排序法的效率高於其它的穩定性排序法。 基數排序也稱為卡片排序,簡而言之,基數排序的原理就是多次利用計數排序(計數排序是一種特殊的桶排序),但是和前面的普通桶排序和計數排序有所區別的是,基數排序並不是將一個整體分配到一個桶中,而是將自身拆分成一個個組成的元素,每個元素分別順序分配放入桶中、順序收集,當從前往後或者從後往前每個位置都進行過這樣順序的分配、收集後,就獲得了一個有序的數列。 在具體實現上如果從左往右那就是**最高位優先(Most Significant Digit first)法**,簡稱MSD法;如果從右往左那就是**最低位優先(Least Significant Digit first)法**,簡稱LSD法。但是不管從最高位開始還是從最低位開始要保證和相同位進行比較,你需要注意的是如果是int等數字型別需要保證從右往左(從低位到高位)保證對齊,如果是字元型別的話需要從左往右(從高位到低位)保證對齊。 ![image-20201113154119682](https://bigsai.oss-cn-shanghai.aliyuncs.com/img/image-20201113154119682.png) 你可能會問為啥不直接將這個數或者這個數按照區間範圍放到對應的桶中,一方面基數排序可能很多時候處理的是字元型的資料,不方便放入某個桶中,另一方面如果數字很大,不方便直接放入桶中。並且基數排序並不需要交換,也不需要比較,就是多次分配、收集得到結果。 ![image-20201113150949762](https://bigsai.oss-cn-shanghai.aliyuncs.com/img/image-20201113150949762.png) 所以遇到這種情況我們基數排序思想很簡單,就拿 934,241,3366,4399這幾個數字進行基數排序的一趟過程來看,第一次會根據各位進行分配、收集: ![image-20201113161050871](https://bigsai.oss-cn-shanghai.aliyuncs.com/img/image-20201113161050871.png) 分配和收集都是有序的,第二次會根據十位進行分配、收集,此次是在第一次個位分配、收集基礎上進行的,所以所有數字單看個位十位是有序的。 ![image-20201113161752292](https://bigsai.oss-cn-shanghai.aliyuncs.com/img/image-20201113161752292.png) 而第三次就是對百位進行分配收集,此次完成之後百位及其以下是有序的。 ![image-20201113162803486](https://bigsai.oss-cn-shanghai.aliyuncs.com/img/image-20201113162803486.png) 而最後一次的時候進行處理的時候,千位有的數字需要補零,這次完畢後後千位及以後都有序,即整個序列排序完成。 ![image-20201113170715860](https://bigsai.oss-cn-shanghai.aliyuncs.com/img/image-20201113170715860.png) 想必看到這裡基數排序的思想你也已經懂了吧,但是雖然懂你不一定能夠寫出程式碼來,繼續看看下面的分析和實現。 ## 數字型別基數排序 有很多時候也有很多時候對基數排序的講解也是基於數字型別的,而數字型別這裡就用int來實現,對於數字型別的基數排序你需要注意的有以下幾點: - 無論是最高位優先法還是最低位優先法進行遍歷需要保證數字各位、十位、百位等對齊,這裡我使用最低位優先法從個位開始向上。 - 數字型別的基數排序需要十個桶(0-9),你可以使用二維陣列,第一維度長度為10表示十個數字,第二個維度為陣列長度,用來儲存數字(因為最壞情況可能當前位數字一樣)。但這樣無疑太浪費記憶體空間了,你可以使用List或者Queue替代,這裡就用List了。 - 具體實現要先找到最大值確定最高多少位,用來進行遍歷時候確認。 - 收集的時候藉助一個自增引數遍歷收集。 - 每次收集完畢十個桶(bucket)需要清空待下次收集。 實現的程式碼為: ```java static void radixSort(int[] arr)//int 型別 從右往左