基数排序
一、算法描述
1.1 核心思想
- 数据有高低位之分,位之间有递进关系
- 高位相等的情况下,才去对比低位大小
- 按照低位到高位的顺序,使用稳定排序算法对每一位排序
1.2 细节解释
数据有高低位之分,比如十进制数字 1232
,字符串 dwsc
,二进制 1001
等等。
这些类型的数据都有高低位,而且是高位大的数据肯定比高位小的数据大。
比如 123
和 234
,123
最高位 1
小于 234
最高位 2
,所以 123 < 234
。
- 基数排序就是利用数据的每一位进行排序,最终得到有序序列的
比如说,数组 [12, 3, 154, 78, 9, 245, 35, 92]
。
因为数字长度不同,所以首先将所有数字补 0 进行长度对齐:
1 2 3 4 5 6 7 8
| 012 003 154 078 009 245 035 092
|
然后按照从低位到高位进行排序:
先按“个位”排序:
1 2 3 4 5 6 7 8 9 10
| 当前数组 取出“个”位 按“个”位排序
012 xx2 012 003 xx3 092 154 xx4 003 078 => xx8 => 154 009 xx9 245 245 xx5 035 035 xx5 078 092 xx2 009
|
再按“十位”排序:
1 2 3 4 5 6 7 8 9 10
| 当前数组 取出“十”位 按“十”位排序
012 x1x 003 092 x9x 009 003 x0x 012 154 => x5x => 035 245 x4x 245 035 x3x 154 078 x7x 078 009 x0x 092
|
再按“百位”排序:
1 2 3 4 5 6 7 8 9 10
| 当前数组 取出“百”位 按“百”位排序
003 0xx 003 009 0xx 009 012 0xx 012 035 => 0xx => 035 245 2xx 078 154 1xx 092 078 0xx 154 092 0xx 245
|
每个“位”都排完之后,就是最终的排序结果了:
1
| [3, 9, 12, 35, 78, 92, 154, 245]
|
基数排序的关键在于从低位往高位排序,这样能保证高位排序是最后的。
二、算法实现
2.1 计算数据的基数
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| int max = Integer.MIN_VALUE; for (int a : arr) { if (a > max) { max = a; } }
int radix = 0; while(max > 0) { max = max / 10; radix++; }
|
2.2 从低位到高位排序
1 2 3 4 5 6
| int exp = 1; for (int i = 0; i < radix; i++) { countSort(arr, exp); exp *= 10; }
|
对每一位进行排序,则使用计数排序(或者其他稳定排序算法也行)。
三、算法分析
3.1 时间复杂度
- 最好时间复杂度:O(n)
- 最坏时间复杂度:O(n)
- 平均时间复杂度:O(n)
3.2 空间复杂度
3.3 稳定性
四、适用场景
- 数据可以分割出“位”来比较
- 数据有高低位之分,位之间有递进关系
- 每一位的数据范围不能太大,要可以用线性排序算法来排序
附录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
|
public class RadixSort implements Sort {
@Override public void sort(int[] arr) { int max = Integer.MIN_VALUE; for (int a : arr) { if (a > max) { max = a; } }
int radix = 0; while(max > 0) { max = max / 10; radix++; }
int exp = 1; for (int i = 0; i < radix; i++) { countSort(arr, exp); exp *= 10; } }
private void countSort(int[] arr, int exp) { int[] counts = new int[10]; for (int a : arr) { counts[(a / exp) % 10]++; }
for (int i = 1; i < counts.length; i++) { counts[i] += counts[i - 1]; }
int[] copy = Arrays.copyOf(arr, arr.length); for (int i = copy.length - 1; i >= 0; i--) { int index = (copy[i] / exp) % 10; counts[index]--; arr[counts[index]] = copy[i]; } }
}
|