定义
基数排序也是非比较的排序算法,对每一位进行排序,从最低位开始排序,复杂度为$O(n * k)$,为数组长度,k为数组中的数的最大的位数;
基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。基数排序基于分别排序,分别收集,所以是稳定的。
算法描述
- 取得数组中的最大数,并取得位数;
- arr为原始数组,从最低位开始取每个位组成radix数组;
- 对radix进行计数排序(利用计数排序适用于小范围数的特点);
动图演示
代码实现
1 2 3 4 5 6 7
| public static void main(String[] args) { int[] array = {3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48}; radixSort(array);
System.out.println(Arrays.toString(array)); }
|
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
|
public static void radixSort(int[] array) { if (array == null || array.length <= 1) { return; }
int length = array.length;
int radix = 10; int[] aux = new int[length]; int[] count = new int[radix + 1]; int x = Arrays.stream(array).map(s -> String.valueOf(s).length()).max().getAsInt();
for (int d = 0; d < x; d++) { for (int i = 0; i < length; i++) { count[digitAt(array[i], d) + 1]++; } for (int i = 0; i < radix; i++) { count[i + 1] += count[i]; }
for (int i = 0; i < length; i++) { aux[count[digitAt(array[i], d)]++] = array[i]; } for (int i = 0; i < length; i++) { array[i] = aux[i]; } for (int i = 0; i < count.length; i++) { count[i] = 0; }
} }
private static int digitAt(int value, int d) { return (value / (int) Math.pow(10, d)) % 10; }
|
算法分析
最佳情况:$T(n) = O(n * k)$
最差情况:$T(n) = O(n * k)$
平均情况:$T(n) = O(n * k)$
基数排序有两种方法:
MSD 从高位开始进行排序 LSD 从低位开始进行排序
基数排序 vs 计数排序 vs 桶排序
这三种排序算法都利用了桶的概念,但对桶的使用方法上有明显差异:
- 基数排序:根据键值的每位数字来分配桶
- 计数排序:每个桶只存储单一键值
- 桶排序:每个桶存储一定范围的数值