前面幾篇博客我們已經陸陸續續的為大家介紹了7種排序方式,今天博客的主題依然與排序算法相關。今天這篇博客就來聊聊基數排序,基數排序算法是不穩定的排序算法,在排序數字較小的情況下,基數排序算法的效率還是比較高的。今天就來聊一下基數排序算法的原理以及代碼的具體實現。
一、基數排序算法示意圖
下方的基數排序算法的實現是利用“桶”來實現的,首先我們創建10個桶,然后按照基數入桶,基數的取值是從數字的低位到高位以此取值。我們還是以[62, 88, 58, 47, 62, 35, 73, 51, 99, 37, 93]這個序列為例,使用基數排序的方式對該序列進行升序排列。
下方截圖就是上述序列基數排序的具體過程,在排序之前我們先得創建10個空桶,並進行0-9的編號。這10個空桶會在基數排序的過程中存儲我們要排序的數值。下方就是對基數排序步驟的詳細介紹:
-
(1)、以無序序列數值的 個數為基數,將無序序列中的值進入到基數對應的桶中。 以51為例,如果取個位數為基數的話,51的基數就為1,那么51就進入如編號為1的桶中。以此類推,62在本輪入桶過程中就進入編號為2的桶中。以個位數為基數入桶的結果如下所示。
-
(2)、個位數為基數入桶完畢后,在安裝編號從小到大將桶中的數據以此取出,在存入我們之前的數組中。如下所示。
-
(3)、在 第二步生成的數組的基礎上再以十位數為基數入桶。入桶完畢后,再次按照桶的編號順序將數值取出。
-
(4)、因為在下方無序的數據中,最大值不超過兩位,所以以十位為基數入桶出桶后就已經是有序的了。如果 最大值是十萬,那么我們一直取基數入桶到十萬位為止。也就是排序的數值越大,我們入桶出桶的次數就越多,所以 隨着位數的增大,排序效率會下降。
二、基數排序算法的代碼實現
看完基數排序的原理后,接下來我們就要給出相應的代碼實現了。當然本篇博客我們依然使用Swift面向對象語言來給出相應的代碼實現。下方代碼的實現主要是按照上述示意圖的步驟,接下來我們就來循序漸進的來看一下代碼的具體實現。
1.創建10個空桶
首先我們需要創建10個空桶,在此我們用一個數組中存放10個數組,這10個數組就是我們相應的桶。而這10個數組所對應的下標就是桶的編號。下方這個createBucket()方法就負責創建10個空桶,並返回。返回結果的類型是Array<Array<Int>>,是一個二維數組。外層數組中存放的就是10個桶,下標是桶的編號。內層數組就是一個桶,負責存放與該桶編號相等的基數對應的數值。具體代碼如下所示。
2.計算無序序列中最大的數值
接着我們要實現一個函數用來計算無序序列中最大的數值,取基數入桶出桶的次數以此最大數值的位數為准。比如最大數值為5位,那么我們取基數就從第一位取到第5位,每取一位基數就要按照該基數進行入桶和出桶操作。下方代碼就是計算無序數列中最大的那個值,代碼還是比較簡單的,如下所示:
3、獲取數字的長度
上面計算完元素后,我們需要計算該最大值的長度。因為長度的值,就是取基數的次數。下面就是獲取數值的長度的函數,其實就是將數字轉換成字符串,字符串再轉換成字符數組,然后返回字符數組的個數。具體代碼如下所示:
4、獲取數值中特定位數的值
下方的函數就是獲取某數字特定位數的值,你可以通過取余以及求模的方式來獲取,以239為例,我想獲取十位數值3,那么我們需要將239執行Int((239%100)/10), 通過該操作,我們就可以獲取十位上的數值。但是在下方函數中並未采用此方法,而是采用將數字轉換成字符串,然后將字符串轉換成字符數組,這樣我們就可以輕松的取出數字中的任何一位。下方就是具體代碼的實現:
5、基數排序的具體代碼實現
萬事俱備只欠東風,上述做的都是基數排序的准備工作,接下來我們就開始調用上述的方法來實現我們的基數排序的具體代碼了。下方就是基數排序的具體代碼,如果上述的幾個函數搞明白了,那么下方代碼並不難理解。先創建桶,獲取無序數列中最大的值,然后獲取這個最大值的長度。然后就是通過for循環不斷的去基數進行入桶和出桶的操作了,如下所示:
三、測試用例
用我RadixSort類遵循了SortType方法,我們依然可以使用之前的測試用例。下方就是我們的測試用例,與之前使用的一直,只不過需要將RadixSort這個類的對象傳給我們的測試函數即可,如下所示:
上述測試用例的輸出結果如下所示:
本篇博客對堆排序的介紹就先到這兒,下篇博客我們將會介紹“各種排序的動態排序過程”的詳細內容。本篇博客的相關代碼依然會在github上進行分享,下方是github分享地址,如下所示:
github代碼分享地址:https://github.com/lizelu/DataStruct-Swift/tree/master/AllKindsOfSort