排序与查找实例(七):基数排序

来源:互联网 发布:mac涂层脱落几年包换屏 编辑:程序博客网 时间:2024/05/28 01:35

    基数排序(radix sorting)将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。 然后从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

     假设有一些二元组(a,b ),要对它们进行以a为首要关键字,b的次要关键字的排序。我们可以先把它们先按照首要关键字排序,分成首要关键字相同的若干堆。然后,在按照次要关键值分别对每一堆进行单独排序。最后再把这些堆串连到一起,使首要关键字较小的一堆排在上面。按这种方式的基数排序称为MSD(Most Significant Dight)排序。第二种方式是从最低有效关键字开始排序,称为LSD(LeastSignificantDight)排序。首先对所有的数据按照次要关键字排序,然后对所有的数据按照首要关键字排序。要注意的是,使用的排序算法必须是稳定的,否则就会取消前一次排序的结果。由于不需要分堆对每堆单独排序,LSD方法往往比MSD简单而开销小。下文介绍的方法全部是基于LSD的。

     基数排序的简单描述就是将数字拆分为个位十位百位,每个位依次排序。因为这对算法稳定要求高,所以我们对数位排序用到上一个排序方法计数排序。因为基数排序要经过d(数据长度)次排序, 每次使用计数排序, 计数排序的复杂度为 On), d 相当于常量和N无关,所以基数排序也是 O(n)。基数排序虽然是线性复杂度, 即对n个数字处理了n次,但是每一次代价都比较高, 而且使用计数排序的基数排序不能进行原地排序,需要更多的内存,并且快速排序可能更好地利用硬件的缓存,所以比较起来,像快速排序这些原地排序算法更可取。对于一个位数有限的十进制数,我们可以把它看作一个多元组,从高位到低位关键字重要程度依次递减。可以使用基数排序对一些位数有限的十进制数排序。

    具体实例及实现代码如下:

    

/**  

 * @Title: RadixSorting.java

 * @Package sortandsearch

 * @Description: TODO

 * @author peidong 

 * @date 2017-5-8 上午10:14:55

 * @version V1.0  

 */

packagesortandsearch;

 

/**

 * @ClassName: RadixSorting

 * @Description: 基数排序实例

 * @date 2017-5-8 上午10:14:55

 *

 */


publicclass RadixSorting {

 

       /**

        *

        *@Title: radixSorting

        *@Description: 基数排序实现

        *@param arr

        *@param d

        *           数组长度

        *@return void

        *@throws

        */

       public static void radixSorting(int[]arr, int d) {

              for (int i = 0; i < d; i++) {

                     // 依次对各位数字进行排序

                     arr = countingSort(arr, i);

                     print(arr, i + 1, 0);

              }

       }

 

       /**

        *

        *@Title: print

        *@Description: 打印

        *@param arr

        *@param k

        *@param d

        *@return void

        *@throws

        */

       public static void print(int[] arr, intk, int d) {

              if (k == d)

                     System.out.println("最终排序结果为:");

              else

                     System.out.println("按第" + k + "位排序后,结果为");

              for (int t : arr) {

                     System.out.print(t + ""); // 输出

              }

              System.out.println();

       }

 

       /**

        *

        *@Title: countingSort

        *@Description: 按位排序实现

        *@return

        *@return int[]

        *@throws

        */

       public static int[] countingSort(int[]arr, int index) {

              // 定义变量

              int k = 9;

              int[] res = new int[arr.length];

              int[] temp = new int[k + 1];

 

              // 赋值与排序

              for (int i = 0; i < k; i++) {

                     temp[i] = 0;

              }

              for (int i = 0; i < arr.length;i++) {

                     int t = getBitData(arr[i],index);

                     temp[t]++;

              }

              for (int i = 1; i <= k; i++) {

                     temp[i] += temp[i - 1];

              }

              for (int i = arr.length - 1; i>= 0; i--) {

                     int m = getBitData(arr[i],index);

                     res[temp[m] - 1] = arr[i];

                     temp[m]--;

              }

              return res;

       }

 

       /**

        *

        *@Title: getBitData

        *@Description: 获取指定位数数据

        *@param data

        *@param index

        *@return

        *@return int

        *@throws

        */

       public static int getBitData(int data,int index) {

              while (data != 0 && index> 0) {

                     data /= 10;

                     index--;

              }

              return data % 10;

       }

 

       /**

        *@Title: main

        *@Description: 测试基数排序

        *@param args

        *@return void

        *@throws

        */

       public static void main(String[] args) {

              // TODO Auto-generated method stub

              int[] arr = new int[] { 326, 453,608, 835, 751, 435, 704, 690, 88, 79, 63, 97};

              System.out.println("基数排序前为:");

              for (int t : arr) {

                     System.out.print(t + "");

              }

              System.out.println();

              radixSorting(arr, 3);

       }

 

}

 

    基数排序的时间复杂度是 O(k·n),其中n是排序元素个数,k是数字位数。注意这不是说这个时间复杂度一定优于O(n·log(n)),因为k的大小一般会受到 n 的影响。 以排序n个不同整数来举例,假定这些整数以B为底,这样每位数都有B个不同的数字,k就一定不小于logB(n)。由于有B个不同的数字,所以就需要B个不同的桶,在每一轮比较的时候都需要平均n·log2(B) 次比较来把整数放到合适的桶中去,所以就有:

          k 大于或等于 logB(n),每一轮(平均)需要 n·log2(B) 次比较

    所以,基数排序的平均时间T就是:

         T ≥ logB(n)·n·log2(B) = log2(n)·logB(2)·n·log2(B) = log2(n)·n·logB(2)·log2(B) = n·log2(n)

    所以和比较排序相似,基数排序需要的比较次数:T ≥ n·log2(n)。故其时间复杂度为 Ω(n·log2(n)) = Ω(n·log n) 。*/

原创粉丝点击