排序算法之基数排序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法之基数排序相关的知识,希望对你有一定的参考价值。

    根据维基百科,基数排序的定义为: 基数排序英语: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

以上是关于排序算法之基数排序的主要内容,如果未能解决你的问题,请参考以下文章

数据结构-排序之基数排序(使用java代码实现)

数据结构之排序算法Java实现—— 基数排序法

十大排序算法之基数排序

算法排序算法之基数排序

数据结构和算法(十七)排序算法之基数排序

排序算法之JAVA基数排序算法