文章目录
一.基数排序介绍
基数排序(radix sort)的思想是多关键字排序,属于分配式排序,它是通过键值的各个位的值,将要排序的元素分配至某些“桶”中,然后依次收集各个桶内数据,通过分配和收集达到排序的目的
基数排序是1887年赫尔曼·何乐礼发明的,它是这样实现的:将整数按位数切割成不同的数字,然后按每个位数分别比较
基数排序示意图
二.执行流程
通过一个例子来介绍基数排序过程
原始序列:80, 43, 155, 987, 100, 31, 6, 299, 155, 0
1.初始桶
每个关键字的每一位都是由“数字”组成的,数字的范围是0~9,所以准备10个桶用来放关键字,这里所说的“桶”,其实是一个先进先出的队列(从桶的上面进,下面出)
2.按照个位分配排序
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
注意观察,最低位有序了,这就是第一趟基数排序后的结果
3.在第一趟排序结果的基础上,按照十位进行分配
80的十位是8放入桶8、100的十位是0放入桶0、0的十位是0放入桶0…以此类推,第二趟分配结果如下图:
依次收集各个桶内数据结果如下:
100,000,006,031,043,155,155,080,987,299
注意观察,十位也已经有序了,这就是第二趟基数排序后的结果(为了方便观察,数字补0到同一长度)
4.在第二趟的基础上进行第三趟分配收集(到了最高位,百位,也是最后一趟)
100的百位是1放入桶1、000的百位是0放入桶0、006的百位是0放入桶0…以此类推,第三趟分配结果如下图:
依次收集各个桶内数据结果如下:
0,6,31,43,80,100,155,155,299,987
现在最高位有序,最高位相同的关键字按中间位有序,中间位相同的关键字按最低位有序,于是整个序列有序,基数排序过程结束
三.代码实现思路
1.定义一个要排序的数组为初始数组
2.定义一个二维数组,即0~9共10个桶,每个桶是一个一维数组,每个一维数组的长度为初始数组的长度
3.定义一个一维数组,用来存储每个桶中数据的个数,由于这个一维数组就是一个桶,所以它的长度为10
4.找到数组中最大的数据,并计算出这个最大值的位数,最大值有几位,循环就进行几次
5.根据最大值的位数开始循环,按照个十百…的顺序依次进行排序
5.1首先取出个位上的数字
5.2把个位上数字对应的数放入对应的桶中
5.3.把全部数据放入完毕后,按照桶0~9的顺序,先进先出的取出并覆盖到初始数组中,注意这里要判断一下,桶中有数据才取
5.4覆盖完毕后,对每一个桶进行清零操作以便下一次循环
四.代码实现
/**
* 基数排序
*/
public class RadixSort {
public static void main(String[] args) {
//定义要排序的数组
// int[] arr = new int[]{34, 512, 36, 67, 89, 6};
int[] arr = new int[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) (Math.random() * 1000);
}
System.out.println("初始数组为:" + Arrays.toString(arr));
//定义二维数组,即0-9共10个桶,每个桶是一个一维数组,这个桶其实就是一个先进先出的队列
int[][] bucket = new int[10][arr.length];
//定义一个一维数组,用来存储每个桶中放入的数字数量
//bucketElementCount[0]即为第一个桶,bucketElementCount[1]即为第二个桶,以此类推...
int[] bucketElementCount = new int[10];
//找出数组中的最大值
//假设第一个数就是最大值
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
//求这个最大值有几位
int maxDigit = (max + "").length();
//定义一个变量用来取出数字的个十百位等
int n = 1;
//开始循环,最大值有几位就循环几次
for (int i = 0; i < maxDigit; i++, n *= 10) {
//按照个十百...的顺序依次比对,即第一次循环按照个位比较,第二次循环按照十位比较...
//定义一个变量用来表示要排序数组的下标
int index = 0;
for (int j = 0; j < arr.length; j++) {
//循环取出数字的个十百位等
int digit = arr[j] / n % 10;
//将数组中的数字放入到与其对应的桶中
bucket[digit][bucketElementCount[digit]] = arr[j];
//桶中放入数字后,数字的数量需要加1
bucketElementCount[digit]++;
}
//按0-9的顺序从桶中先进先出的取出数据覆盖到原数组
for (int k = 0; k < bucketElementCount.length; k++) {
//判断桶中是否有数据,有数据才取出
if (bucketElementCount[k] != 0) {
//代码走到这里说明桶中有数据
for (int l = 0; l < bucketElementCount[k]; l++) {
//将桶中的数据覆盖到原数组中
arr[index] = bucket[k][l];
index++;
}
}
//每一轮需要把桶中的数据清零以便下一轮继续存储
bucketElementCount[k] = 0;
}
System.out.println("第" + (i + 1) + "轮排序为:" + Arrays.toString(arr));
}
}
}