上一篇提到了计数排序,它在输入序列元素的取值范围较小时,表现不俗。但是,现实生活中不总是满足这个条件,比如最大整形数据可以达到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
1)算法属于分配排序
2)平均时间复杂度是O(b/r(2r+n)), b-每个元素的bit数,r-每个元素划分成b/r个数字,每个数字r个bit。当r=log2n时,复杂度是O(2bn/log2n),也就是说,当b=O(log2n)时,时间复杂度是O(n).
3) 空间复杂度是O(2r+n)
4)算法属于稳定排序
(二)算法仿真
下面对随机化快速排序和基数排序,针对不同输入整数序列长度,仿真结果如下,从结果看,当输入序列长度越大,基数排序性能越优越。
**************************************************
Number to Sort is:2500
Array to sort is:{1642670374,460719485,1773719101,2140462092,1260791250,199719453,1290828881,1946941575,2032337910,643536338...}
Cost time of 【RadixSort】 is(milliseconds):48
Sort result of 【RadixSort】:{217942,491656,1389218,2642908,3608001,3976751,4905471,5094692,6340348,7693772...}
Cost time of 【RandomizedQuickSort】 is(milliseconds):1
Sort result of 【RandomizedQuickSort】:{217942,491656,1389218,2642908,3608001,3976751,4905471,5094692,6340348,7693772...}
**************************************************
Number to Sort is:25000
Array to sort is:{987947608,1181521142,1240568028,373349221,289183678,2051121943,1257313984,745646081,1414556623,1859315040...}
Cost time of 【RadixSort】 is(milliseconds):1
Sort result of 【RadixSort】:{47434,109303,240122,255093,448360,526046,526445,628228,837987,966240...}
Cost time of 【RandomizedQuickSort】 is(milliseconds):2
Sort result of 【RandomizedQuickSort】:{47434,109303,240122,255093,448360,526046,526445,628228,837987,966240...}
**************************************************
Number to Sort is:250000
Array to sort is:{1106960922,1965236858,1114033657,1196235697,2083563075,1994568819,1185250879,670222217,1386040268,1316674615...}
Cost time of 【RadixSort】 is(milliseconds):7
Sort result of 【RadixSort】:{466,884,8722,35382,37181,44708,53396,55770,67518,74898...}
Cost time of 【RandomizedQuickSort】 is(milliseconds):27
Sort result of 【RandomizedQuickSort】:{466,884,8722,35382,37181,44708,53396,55770,67518,74898...}
**************************************************
Number to Sort is:2500000
Array to sort is:{1903738012,485657780,1747057138,2082998554,1658643001,91586227,2127717572,557705232,533021562,1322007386...}
Cost time of 【RadixSort】 is(milliseconds):81
Sort result of 【RadixSort】:{369,392,1316,1378,2301,3819,4013,4459,5922,6423...}
Cost time of 【RandomizedQuickSort】 is(milliseconds):340
Sort result of 【RandomizedQuickSort】:{369,392,1316,1378,2301,3819,4013,4459,5922,6423...}
**************************************************
Number to Sort is:25000000
Array to sort is:{2145921976,298753549,11187940,410746614,503122524,1951513957,1760836125,2141838979,1702951573,1402856280...}
Cost time of 【RadixSort】 is(milliseconds):1,022
Sort result of 【RadixSort】:{130,145,406,601,683,688,736,865,869,954...}
Cost time of 【RandomizedQuickSort】 is(milliseconds):3,667
Sort result of 【RandomizedQuickSort】:{130,145,406,601,683,688,736,865,869,954...}
相关源码:
1 package com.cnblogs.riyueshiwang.sort; 2 3 import java.util.Arrays; 4 5 public class RadixSort extends abstractSort { 6 7 @Override 8 protected void sort(int[] toSort) { 9 // number to sort, n integers 10 int n = toSort.length; 11 // b bits each integer 12 int b = Integer.SIZE; 13 /* 14 * Split each integer into b/r digits, and each r bits long. So average 15 * running time is O(b/r(2^r+n)). It is proved that running time is 16 * close to least time while choosing r to lgn. 17 */ 18 int r = (int) Math.ceil(Math.log(n) / Math.log(2)); 19 // considering the space cost, the maximum of r is 16. 20 r = Math.min(r, 16); 21 22 int upperLimit = 1 << r; 23 int loopCount = b / r; 24 int j = 0; 25 int[] resultArray = new int[toSort.length]; 26 int[] countingArray = new int[upperLimit]; 27 while (j < loopCount) { 28 int rightShift = j * r; 29 radixSort(toSort, upperLimit, rightShift, resultArray, 30 countingArray); 31 Arrays.fill(countingArray, 0); 32 j++; 33 } 34 int mod = b % r; 35 if (mod != 0) { 36 upperLimit = 1 << mod; 37 int rightShift = r * loopCount; 38 countingArray = new int[upperLimit]; 39 radixSort(toSort, upperLimit, rightShift, resultArray, 40 countingArray); 41 } 42 } 43 44 private void radixSort(int[] toSort, int upperLimit, int rightShift, 45 int[] resultArray, int[] countingArray) { 46 int allOnes = upperLimit - 1; 47 for (int i = 0; i < toSort.length; i++) { 48 int radix = (toSort[i] >> rightShift) & allOnes; 49 countingArray[radix]++; 50 } 51 for (int i = 1; i < countingArray.length; i++) { 52 countingArray[i] += countingArray[i - 1]; 53 } 54 55 for (int i = toSort.length - 1; i >= 0; i--) { 56 int radix = (toSort[i] >> rightShift) & allOnes; 57 resultArray[countingArray[radix] - 1] = toSort[i]; 58 countingArray[radix]--; 59 } 60 System.arraycopy(resultArray, 0, toSort, 0, resultArray.length); 61 } 62 63 public static void main(String[] args) { 64 for (int j = 0, n = 2500; j < 5; j++, n = n * 10) { 65 System.out 66 .println("**************************************************"); 67 System.out.println("Number to Sort is:" + n); 68 int upperLimit = Integer.MAX_VALUE; 69 int[] array = CommonUtils.getRandomIntArray(n, upperLimit); 70 System.out.print("Array to sort is:"); 71 CommonUtils.printIntArray(array); 72 73 int[] array1 = Arrays.copyOf(array, n); 74 new RadixSort().sortAndprint(array1); 75 76 int[] array2 = Arrays.copyOf(array, n); 77 new RandomizedQuickSort().sortAndprint(array2); 78 } 79 } 80 }
RadixSort.java