介绍
基数排序(桶排序)介绍:
1)基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是通过键值的各个位的值,将要排序的元素分配至某些“桶”中,达到排序的作用
2)基数排序法是属于稳定性的排序,基数排序法的是效率高的稳定性排序法
3)基数排序(Radix Sort)是桶排序的扩展
4)基数排序是1887年赫尔曼·何乐礼发明的。它是这样实现的:将整数按位数切割成不同的数字,然后按每个位数分别比较。
基本思想
1)将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
2)这样说明,比较难理解,下面我们看一个图文解释,理解基数排序的步骤
数组的初始状态
arr = {53, 3, 542, 748, 14, 214}
第1轮排序:
(1) 将每个元素的个位数取出,然后看这个数应该放在哪个对应的桶(一个一维数组)
(2) 按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数组)
数组的第1轮排序结果:
arr = {542, 53, 3, 14, 214, 748}
第2轮排序:
(1) 将每个元素的十位数取出,然后看这个数应该放在哪个对应的桶(一个一维数组)
(2) 按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数组)
数组的第2轮排序结果:
arr = {3, 14, 214, 542, 748, 53}
第3轮排序:
(1) 将每个元素百位数取出,然后看这个数应该放在哪个对应的桶(一个一维数组)
(2) 按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数组)
数组的第3轮排序结果:
arr = {3, 14, 53, 214, 542, 748}
代码实现
import java.time.Duration;
import java.time.LocalTime;
import java.util.Arrays;
public class RadixSort {
public static void main(String[] args) {
// test1();
// test2();
test3();
}
public static void test1() {
int arr[]={53, 3, 542, 748, 14, 214};
System.out.println("排序前:");
printArr(arr);
radixSort(arr);
System.out.println("排序后:");
printArr(arr);
}
public static void test2() {
int len=12;
int arr[]=new int [len];
for(int i=0;i<len;i++) {
arr[i]=(int) (Math.random()*100);
}
System.out.println("排序前:");
printArr(arr);
radixSort(arr);
System.out.println("排序后:");
printArr(arr);
}
public static void test3() {
int len =80000;
int arr[] = new int [len];
for(int i=0;i<len;i++) {
arr[i]=(int) (Math.random()*1000);
}
LocalTime before=LocalTime.now();
System.out.println("排序前的时间:"+before);
radixSort(arr);
LocalTime after=LocalTime.now();
Duration dur=Duration.between(before, after);
System.out.println("排序后的时间:"+after);
System.out.println("时间差(毫秒):"+dur.toMillis());
}
private static void radixSort(int[] arr) {
int maxLen=getDigitLen(arr);
int bucket[][]=new int [10][arr.length];
int [] bucketElementCount=new int [10];
// 外层for要按照maxlen个位数排序
for(int i=0 , n=1;i<maxLen;i++,n*=10) {
//按照第i位数的大小 对每个数进行排序
for(int j=0;j<arr.length;j++) {
int num=arr[j] / n % 10;
//把位数 num 放到对应的桶中
int count=bucketElementCount[num];
bucket[num][count]=arr[j];
//第num个桶,的元素数量+1
++bucketElementCount[num];
}
arr=clearBucket(bucket, bucketElementCount,arr);
//把所有的桶清空
Arrays.fill(bucketElementCount, 0);
}
}
private static int[] clearBucket(int[][] bucket, int[] bucketElementCount, int[] arr) {
int index=0;
//按照1维数组的下标,把元素放到原来数组中
for(int i=0;i<bucketElementCount.length;i++) {
//第i个桶的是否有元素
int amount=bucketElementCount[i];
if(amount != 0) {
//把第i个桶的元素拿出来
// 遍历第i个桶的第j个小格子
for(int j=0;j<amount;j++)
arr[index++]=bucket[i][j];
}
//把第i个桶的元素拿出来后,把这个桶清空,
//通过把桶数量赋值为0 就可以实现清空
// bucketElementCount[i]=0;
}
// System.out.println("第i轮排序结果:"+Arrays.toString(arr));
return arr;
}
//获取最大数有多少 个 位数
private static int getDigitLen(int[] arr) {
int max=arr[0];
for(int i=1;i<arr.length;i++) {
if(arr[i]>max) {
max=arr[i];
}
}
return String.valueOf(max).length();
}
//打印数组
private static void printArr(int[] arr) {
for(int i=0;i<arr.length;i++) {
System.out.print(arr[i]+" ");
}
System.out.println();
}
}
运行结果:
test2
test3
说明:
基数排序的说明:
1)基数排序是对传统桶排序的扩展,速度很快.
2)基数排序是经典的空间换时间的方式,占用内存很大, 当对海量数据排序时,容易造成 OutOfMemoryError 。
3)基数排序时稳定的。[注:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的]
4)有负数的数组,我们不用基数排序来进行排序, 如果要支持负数,参考: https://code.i-harness.com/zh-CN/q/e98fa9https://code.i-harness.com/zh-CN/q/e98fa9