基本介绍
基数排序(radix sort)的思想是多关键字排序,属于分配式排序。它是通过键值的各个位的值,将要排序的元素分配至某些“桶”中,然后依次收集各个桶内数据,通过分配和收集达到排序的目的。
基数排序是1887年赫尔曼·何乐礼发明的。它是这样实现的:将整数按位数切割成不同的数字,然后按每个位数分别比较。
基数排序示意图:
执行流程
下面通过一个例子来体会基数排序过程。
原始序列:80, 43, 155, 987, 100, 31, 6, 299, 155, 0
0)初始桶
每个关键字的每一位都是由“数字”组成的,数字的范围是0~9,所以准备10个桶用来放关键字。 要注意的是,组成关键字的每一位不一定是数字。如果关键字有一位是英文字母那么按这一位排序时,就要准备26个桶(假设不区分大小写)。这里所说的“桶”,其实是一个先进先出的队列(从桶的上面进,下面出)。
1)进行第一趟分配和收集,要按照最后一位(个位)分配。
分配过程如下(注意,关键字从桶的上面进入):
80的最低位是0放入桶0、43最低位是3放入桶3、155最低位是5放入桶5…以此类推,第一趟分配结果如下图: 收集过程是这样的:按桶0到桶9的顺序收集,注意关键字从桶的下面出。 桶0:80,100,0 桶1:31 桶2:没有关键字不收集 . . . 桶9:299 将每桶收集的关键字依次排开,所以第一趟收集后的结果为: 80,100,0,31,43,155,155,6,987,299 注意观察,最低位有序了,这就是第一趟基数排序后的结果。
2)在第一趟排序结果的基础上,按照十位进行分配
80的十位是8放入桶8、100的十位是0放入桶0、0的十位是0放入桶0…以此类推,第二趟分配结果如下图: 依次收集各个桶内数据结果如下: 100,000,006,031,043,155,155,080,987,299 注意观察,十位也已经有序了,这就是第二趟基数排序后的结果(为了方便观察,数字补0到同一长度)。
3)在第二趟的基础上进行第三趟分配收集(到了最高位 百位,也是最后一趟)
100的百位是1放入桶1、000的百位是0放入桶0、006的百位是0放入桶0…以此类推,第三趟分配结果如下图: 依次收集各个桶内数据结果如下: 0,6,31,43,80,100,155,155,299,987
现在最高位有序,最高位相同的关键字按中间位有序,中间位相同的关键字按最低位有序,于是整个序列有序,基数排序过程结束。
代码实现
public class RadixSortDemo {
public static void main(String[] args) {
int[] array = new int[]{80, 43, 155, 987, 100, 31, 6, 299, 155, 0};
radixSort(array);
System.out.println(Arrays.toString(array));
}
public static void radixSort(int[] array) {
int max = array[0];
for (int item : array) {
if (item > max) {
max = item;
}
}
int maxLength = (max + "").length();
int[][] buckets = new int[10][array.length];
int[] bucketElementCounts = new int[10];
for (int i = 0, n = 1; i < maxLength; i++, n *= 10) {
for (int element : array) {
int digitOfElement = element / n % 10;
buckets[digitOfElement][bucketElementCounts[digitOfElement]] = element;
bucketElementCounts[digitOfElement]++;
}
int index = 0;
for (int k = 0; k < bucketElementCounts.length; k++) {
if (bucketElementCounts[k] != 0) {
for (int l = 0; l < bucketElementCounts[k]; l++) {
array[index] = buckets[k][l];
index++;
}
}
bucketElementCounts[k] = 0;
}
System.out.println("第" + (i + 1) + "轮排序:" + Arrays.toString(array));
}
}
}
运行结果
第1轮排序:[80, 100, 0, 31, 43, 155, 155, 6, 987, 299]
第2轮排序:[100, 0, 6, 31, 43, 155, 155, 80, 987, 299]
第3轮排序:[0, 6, 31, 43, 80, 100, 155, 155, 299, 987]
[0, 6, 31, 43, 80, 100, 155, 155, 299, 987]
序列包含负数的解决思路
- 将所有的数加一个数,使得所有的数变为正数或0进行基数排序;
- 排序完之后在减掉加的数值输出。
- 注意:这里加的数是指大于等于最小数的绝对值的数
🥳
|