排序算法之基數排序
根據維基百科,基數排序的定義為: 基數排序(英語:Radix sort)是一種非比較型整數排序算法,其原理是將整數按位數切割成不同的數字,然後按每個位數分別比較。由於整數也可以表達字符串(比如名字或日期)和特定格式的浮點數,所以基數排序也不是只能使用於整數。
基數排序的思路是將所有待比較數值(正整數)統一為同樣的數位長度,數位較短的數前面補零. 然後, 從最低位開始, 依次進行一次穩定排序,這樣從最低位排序一直到最高位排序完成以後, 數列就變成一個有序序列.
舉個栗子:
待排序數列為:324,63,59,225,13
第一次排序(按個位大小排序):063,013,324,225,059
第二次排序(按十位大小排序):013,324,225,059,063
第三次排序(按百位大小排序):013,059,063,225,324
最終輸出:13,59,63,225,324
從這個例子可以看出:下一次的排序不會影響上一次排序的結果,即當按照十位排序時如果十位上的數字相同,則它們的排序依然是上一次排序的結果(上述例子中的324與225),所以我們需要穩定排序。什麽是穩定排序?
穩定排序的意思是指, 待排序相同元素之間的相對前後關系,在各次排序中不會改變.比如實例中具有十位數字2的兩個數字324和225, 在十位排序之前324在225之前,在十位排序之後, 324依然在225之前。穩定排序能保證,上一次的排序成果被保留,十位數的排序過程能保留個位數的排序成果,百位數的排序過程能保留十位數的排序成果.
代碼實現上述過程時我們用數組來存放數據和排序結果:
第一次排序(個位數)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
63 | 324 | 225 | 59 | ||||||
13 | |||||||||
第二次排序(十位數)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
13 | 324 | 59 | 63 | ||||||
225 | |||||||||
第三次排序(百位數)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
013 | 225 | 324 | |||||||
059 | |||||||||
063 |
最終將二維數組中的元素按列讀出來就是所得結果:
13,59,63,225,324
代碼實現:
package acm; /*基數排序*/ class RadxSort { public void RSort(int[] ary){ int length = ary.length; int[][] bucket = new int[length][10];//桶用來存放按位排序的數 int[] order = new int[10]; //記錄一個桶中有多少個元素 int time = 1;//記錄排序次數,即最大數的位數 int n = 1; int k = 0; while(time<=maxDigit(ary)){ for(int i:ary){ int digit = (i/n)%10; //從個位依次往上每位上的數 bucket[order[digit]][digit] = i; order[digit]++;//把桶中的個數加一 } for(int i=0;i<10;i++){ if(order[i]!=0){ for(int j=0;j<order[i];j++){ ary[k] = bucket[j][i];//把同一個桶中的數據全讀出來,即從上往下讀 k++; } } order[i] = 0; //將記錄個數清零,用以下一次排序 } n*=10; k = 0; time++; } } //找出數組中最大數有多少位 int maxDigit(int[] ary){ int max=0; int n = 1; for(int i=0;i<ary.length;i++){ if(max<ary[i]) max = ary[i]; } while(max/10 != 0){ max = max/10; n++; } return n; } } public class RadixSort{ public static void main(String[] args){ int[] ary = new int[]{87,15,2,47,456,987,4561,5}; RadxSort RS = new RadxSort(); RS.RSort(ary); for(int num:ary){ System.out.print(num+","); } } }
算法復雜度分析
基數排序的時間復雜度是{\displaystyle O(k\cdot n)},其中{\displaystyle n}是排序元素個數,{\displaystyle k}是數字位數。註意這不是說這個時間復雜度一定優於{\displaystyle O\left(n\cdot \log \left(n\right)\right)},{\displaystyle k}的大小取決於數字位的選擇(比如比特位數),和待排序數據所屬數據類型的全集的大小;{\displaystyle k}決定了進行多少輪處理,而{\displaystyle n}是每輪處理的操作數目。
以排序{\displaystyle n}個不同整數來舉例,假定這些整數以{\displaystyle B}為底,這樣每位數都有{\displaystyle B}個不同的數字,{\displaystyle k=\log _{B}N},{\displaystyle N}是待排序數據類型全集的勢。雖然有{\displaystyle B}個不同的數字,需要{\displaystyle B}個不同的桶,但在每一輪處理中,判斷每個待排序數據項只需要一次計算確定對應數位的值,因此在每一輪處理的時候都需要平均{\displaystyle n}次操作來把整數放到合適的桶中去,所以就有:
{\displaystyle k\approx \log _{B}N}
所以,基數排序的平均時間{\displaystyle T}就是:
{\displaystyle T\approx \log _{B}\left(N\right)\cdot n}
其中前一項是一個與輸入數據無關的常數,當然該項不一定小於{\displaystyle \log n}。
如果考慮和比較排序進行對照,基數排序的形式復雜度雖然不一定更小,但由於不進行比較,因此其基本操作的代價較小,而且在適當選擇的{\displaystyle B}之下,{\displaystyle k}一般不大於{\displaystyle \log n},所以基數排序一般要快過基於比較的排序,比如快速排序。
本文出自 “衛莨” 博客,請務必保留此出處http://acevi.blog.51cto.com/13261784/1982167
排序算法之基數排序