1. 程式人生 > >排序算法之基數排序

排序算法之基數排序

java 算法 排序

根據維基百科,基數排序的定義為: 基數排序英語: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

排序算法之基數排序