上一篇提到了计数排序,它在输入序列元素的取值范围较小时,表现不俗。但是,现实生活中不总是满足这个条件,比如最大整形数据可以达到231-1,这样就存在2个问题:

1)因为m的值很大,不再满足m=O(n),计数排序的时间复杂也就不再是线性的;

2)当m很大时,为计数数组申请的内存空间会很大;

为解决这两个问题,本篇讨论基数排序(Radix sort),基数排列的思想是:

1)将先按照某个基数将输入序列的每个元素划分成若干部分,每个部分对排序结果的影响是有优先级的;

2)先按低优先级排序,再按高优先级排序,依次递推。这里要注意,每个部分进行排序时,必须选用稳定排序算法,例如基数排序。

3)最后的次序就是高优先级高的在前,高优先级相同的,低优先级高的在前。

 (一)算法实现

 1     @Override
 2     protected void sort(int[] toSort) {
 3         // number to sort, n integers
 4         int n = toSort.length;
 5         // b bits each integer
 6         int b = Integer.SIZE;
 7         /*
 8          * Split each integer into b/r digits, and each r bits long. So average
 9          * running time is O(b/r(2^r+n)). It is proved that running time is
10          * close to least time while choosing r to lgn.
11          */
12         int r = (int) Math.ceil(Math.log(n) / Math.log(2));
13         // considering the space cost, the maximum of r is 16.
14         r = Math.min(r, 16);
15 
16         int upperLimit = 1 << r;
17         int loopCount = b / r;
18         int j = 0;
19         int[] resultArray = new int[toSort.length];
20         int[] countingArray = new int[upperLimit];
21         while (j < loopCount) {
22             int rightShift = j * r;
23             radixSort(toSort, upperLimit, rightShift, resultArray,
24                     countingArray);
25             Arrays.fill(countingArray, 0);
26             j++;
27         }
28         int mod = b % r;
29         if (mod != 0) {
30             upperLimit = 1 << mod;
31             int rightShift = r * loopCount;
32             countingArray = new int[upperLimit];
33             radixSort(toSort, upperLimit, rightShift, resultArray,
34                     countingArray);
35         }
36     }
37 
38     private void radixSort(int[] toSort, int upperLimit, int rightShift,
39             int[] resultArray, int[] countingArray) {
40         int allOnes = upperLimit - 1;
41         for (int i = 0; i < toSort.length; i++) {
42             int radix = (toSort[i] >> rightShift) & allOnes;
43             countingArray[radix]++;
44         }
45         for (int i = 1; i < countingArray.length; i++) {
46             countingArray[i] += countingArray[i - 1];
47         }
48 
49         for (int i = toSort.length - 1; i >= 0; i--) {
50             int radix = (toSort[i] >> rightShift) & allOnes;
51             resultArray[countingArray[radix] - 1] = toSort[i];
52             countingArray[radix]--;
53         }
54         System.arraycopy(resultArray, 0, toSort, 0, resultArray.length);
55     }
radixSort

相关文章: