基数排序及优化详解

  本系列文章共有十一篇:
    冒泡排序及优化详解
    快速排序及优化详解
    插入排序及优化详解
    希尔排序及优化详解
    选择排序及优化详解
    归并排序及优化详解
    堆排序详解
    计数排序及优化详解
    桶排序详解
    基数排序及优化详解
    十大排序算法的比较与性能分析

一、基数排序基础

  基数排序是一种非比较型整数排序算法,其基本思想是:将整数按位数切割成不同的数字,然后按每个位数分别比较。
  基数排序的具体做法是:
   1>将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。
   2>从最低位开始,依次进行一次排序。
   3>依次从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。

1.1 基数排序图示

  以数组[11,54,46,25,23]为例,由于各元素位数相同,所以不用进行补位。先从个位开始进行比较排序,数组变成[11,23,54,25,46]。再按十位进行比较排序,数组变成[11,23,25,46,54],排序完成,图示如下:

1.2 基数排序实现

  将上述过程用代码实现,示例为:

    static void radixSort(int[] array, int digit) {
    	/*此处桶数之所以取10,是因为数字0-9总共是十个数字,因此每趟比较时,分为10个桶*/
        int radix = 10; 
        int i = 0, j = 0;
        /*存放各个桶的数据统计个数*/
        int[] count = new int[radix]; 
        int[] bucket = new int[array.length];
        /*按照从低位到高位的顺序执行排序过程*/
        for (int d = 1; d <= digit; d++) {
	       /*置空各个桶的数据统计*/
           for (i = 0; i < radix; i++) {
                count[i] = 0;
           }
           /*统计各个桶将要装入的数据个数*/
           for (i = 0; i <array.length; i++) {
               j = getDigit(array[i], d);
               count[j]++;
           }
           /*count[i]表示第i个桶的右边界索引*/
           for (i = 1; i < radix; i++) {
                count[i] = count[i] + count[i - 1];
           }
           /*将数据依次装入桶中,这里要从右向左扫描,保证排序稳定性*/
           for (i = array.length-1; i >= 0; i--) {
              j = getDigit(array[i], d);
              /*求出元素的第k位的数字, 例如:576的第3位是5*/
              bucket[count[j] - 1] = array[i];
              /*放入对应的桶中,count[j]-1是第j个桶的右边界索引,对应桶的装入数据索引减一*/
              count[j]--; // 
          }
          /*将已分配好的桶中数据再倒出来,此时已是对应当前位数有序的表*/
          for (i = 0, j = 0; i < array.length; i++, j++) {
           	  array[i] = bucket[j];
          }
        }
     }
    
   /*获取x这个数的d位数上的数字,比如获取123的1位数,结果返回3*/
   static int getDigit(int num, int d) {
   	   /*本实例中的最大数是百位数,所以只要到100就可以了*/
       int digit[] = {1, 10, 100};
       return ((num/digit[d-1]) % 10);
    }

二、基数排序优化

  基数排序的优化多在于getDigit方法,即获取对应位数的数字上,如常规的该方法实现为:

int getDigit(int n,int i)
{
    int p=(int)pow(radix,i);
    return (int)(n*p)%radix;
}

  pow方法的调用,可能会影响速度,可改为上面示例代码中的实现方法:

   static int getDigit(int num, int d) {
       int digit[] = {1, 10, 100};
       return ((num/digit[d-1]) % 10);
    }

三、稳定性、复杂度及适用场景

3.1 稳定性

  基数排序是稳定的排序方法。

3.2 复杂度

  在基数排序中,r为基数,d为位数。则基数排序的时间复杂度为O(d(n+r))。

3.3 适用场景

  基数排序的适用场景和计数排序类似,即待排序序列是在一定范围内的整数。

扫描二维码关注公众号,回复: 11426605 查看本文章

猜你喜欢

转载自blog.csdn.net/m0_37741420/article/details/107140825