7.11基数排序
基数排序(桶排序)介绍:
1、 基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶 子法”(bucket sort)或bin sort,顾名思义,它是通过键值的各个位的值, 将要排序的元素分配至某些“桶”中,达到排序的作用
2、 基数排序法是属于稳定性的排序,基数排序法的是效率高的稳定性排序法
3、 基数排序(Radix Sort)是桶排序的扩展
4、 基数排序是1887年赫尔曼·何乐礼发明的。它是这样实现的:将整数按位数切割成不同的数字,然后按每个位数分别比较
基数排序基本思想:
将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。然后, 从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列
基数排序的步骤说明:
1、 第一轮按照个位数字进行排序
2、 第二轮按照十位数字进行排序
3、 第三轮按照百位数字进行排序
4、 以此类推
基数排序的说明:
1、 基数排序是对传统桶排序的扩展,速度很快
2、 基数排序是经典的空间换时间的方式,占用内存很大, 当对海量数据排序时, 容易造成 OutOfMemoryError
3、 基数排序时稳定的。[注:假定在待排序的记录序列中,存在多个具有相同的关键字的记录, 若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的]
4、 有负数的数组,我们不用基数排序来进行排序
package com.atguigu06.sort;
import java.util.Arrays;
/**
* @author peng
* @date 2021/11/22 - 19:52
* <p>
* 实现桶排序:
* 1、创建0-9,九个桶(实质上是九个一维数组);
* 2、将需要排序的数,按照个位的数分配到九个桶之中;
* 3、再根据桶的顺序将每个桶中数字放回到数组中;
* 4、再按照十位的数字分配到各个桶中;
* 5、再根据顺序将桶中的数字放回到数组之中
* 6、以此类推,直到数组的顺序不再发生变化。
*/
public class RadixSort {
public static void main(String[] args) {
int[] array = {53, 3, 542, 748, 14, 214};//需要排序的数组
System.out.println("排序前的数组为:");
System.out.println(Arrays.toString(array));
//调用基数排序算法
radixSort(array);
System.out.println("排序后的数组为:");
System.out.println(Arrays.toString(array));
}
/**
* 实现基数排序算法
*/
public static void radixSort(int[] array) {
//首先定义一个二维数组表示10个桶
int[][] bucket = new int[10][array.length];//基数排序算法是空间换取时间的算法
int[] bucketCount = new int[10];//用于记录每一个桶中元素的个数
//先求出整个数组的最大位数是多少位,所以要先找到数组的最大值
int max = array[0];//假设第一个是最大值
for (int i = 1; i < array.length; i++) {
//注意一个小细节,这里遍历数组是从1开始的
if (array[i] > max) {
max = array[i];
}
}
//for循环之后就找到了最大值,现在要知道最大值的位数是多少
//一个最简单的办法就是将数字转换成字符串,然后直接统计字符串的长度就可以了
int maxlength = (max + "").length();//将数字和空字符串拼接之后变成了字符串,再统计字符串的长度
for (int k = 0; k < maxlength; k++) {
//遍历最大的长度,这就是要进行装桶的次数
for (int i = 0; i < array.length; i++) {
//遍历数组中的每一个数
int digitOfElement = array[i] / (10 ^ k) % 10;//获取元素轮数对应的位数数字
bucket[digitOfElement][bucketCount[digitOfElement]] = array[i];//将对应的数放在对应的桶中,并且计数
bucketCount[digitOfElement]++;//因为放进了一个数,所以要加一
}
//按照桶的顺序将桶中元素放回到数组之中
//遍历每一个桶,并将桶中的数据放回到数组之中
int index = 0;//等下将桶中数据放回数组中时,要用到
for (int i = 0; i < bucket.length; i++) {
if (bucketCount[i] != 0) {
//如果桶中的数据不为0,遍历这个桶,将桶中的数据放回到数组之中
for (int j = 0; j < bucketCount[i]; j++) {
array[index] = bucket[i][j];//将桶中的数据放回到数组之中
index++;
}
//将桶中记录元素的数字清理掉
//在原视频中,老师将【bucketCount[i] = 0;】放在if之外,我认为桶中只有有数据才能进入if里面,就是说有数据的桶才需要清0
//在if之外清0,那么那些没有数据的桶也会进行清0操作,显然这是走多了一步
bucketCount[i] = 0;
}
}
}
// //第一轮
// //遍历最大的长度,这就是要进行装桶的次数
// for (int i = 0; i < array.length; i++) {
// //遍历数组中的每一个数
// int digitOfElement = array[i] / (10 ^ k) % 10;//获取元素的个位数字
// bucket[digitOfElement][bucketCount[digitOfElement]] = array[i];//将对应的数放在对应的桶中,并且计数
// bucketCount[digitOfElement]++;//因为放进了一个数,所以要加一
// }
// //按照桶的顺序将桶中元素放回到数组之中
// //遍历每一个桶,并将桶中的数据放回到数组之中
// int index = 0;//等下将桶中数据放回数组中时,要用到
// for (int i = 0; i < bucket.length; i++) {
// if (bucketCount[i] != 0) {
// //如果桶中的数据不为0,遍历这个桶,将桶中的数据放回到数组之中
// for (int j = 0; j < bucketCount[i]; j++) {
// array[index] = bucket[i][j];//将桶中的数据放回到数组之中
// index++;
// }
// //将桶中记录元素的数字清理掉
// //在原视频中,老师将【bucketCount[i] = 0;】放在if之外,我认为桶中只有有数据才能进入if里面,就是说有数据的桶才需要清0
// //在if之外清0,那么那些没有数据的桶也会进行清0操作,显然这是走多了一步
// bucketCount[i] = 0;
// }
// }
//
// //进行第二轮的排序
// //第一步:将数组中的元素按照十位数的顺序放进桶中
// for (int i = 0; i < array.length; i++) {
// int digitOfElement = array[i] / 10 % 10;//获取元素的十位上的数字
// //将元素按照数字放在对应的桶中
// bucket[digitOfElement][bucketCount[digitOfElement]] = array[i];//将数字放在对应的桶中
// bucketCount[digitOfElement]++;//桶中的数量加一
// }
// //第二步:将桶中的数字按照桶的顺序取出,放回到数组中去
// index = 0;//数组的索引要重新置为0
// for (int i = 0; i < bucket.length; i++) {
// if (bucketCount[i] != 0) {
// //如果该桶中的数量不为0,说明该桶中是有元素的,如果为0 ,则说明没有元素就可以直接跳过这个桶了
// for (int j = 0; j < bucketCount[i]; j++) {
// //遍历有数据的桶, 将桶中的数据放回到数组中去
// array[index] = bucket[i][j];
// index++;
// }
// //每遍历完一个桶,要将桶中数据置为0
// bucketCount[i] = 0;
// }
// }
//
// //进行第三轮的排序
// //第一步:将数组中的元素按照十位数的顺序放进桶中
// for (int i = 0; i < array.length; i++) {
// int digitOfElement = array[i] / 100 % 10;//获取元素的十位上的数字
// //将元素按照数字放在对应的桶中
// bucket[digitOfElement][bucketCount[digitOfElement]] = array[i];//将数字放在对应的桶中
// bucketCount[digitOfElement]++;//桶中的数量加一
// }
// //第二步:将桶中的数字按照桶的顺序取出,放回到数组中去
// index = 0;//数组的索引要重新置为0
// for (int i = 0; i < bucket.length; i++) {
// if (bucketCount[i] != 0) {
// //如果该桶中的数量不为0,说明该桶中是有元素的,如果为0 ,则说明没有元素就可以直接跳过这个桶了
// for (int j = 0; j < bucketCount[i]; j++) {
// //遍历有数据的桶, 将桶中的数据放回到数组中去
// array[index] = bucket[i][j];
// index++;
// }
// //每遍历完一个桶,要将桶中数据置为0
// bucketCount[i] = 0;
// }
// }
}
}