这篇文章你可以了解如下知识:
- 你可以学习到基数的排序的思想
- 可以学习用java实现基数排序
- 主页也有全部的所有排序算法知识点,可以参考一下
系列文章
- 各种排序算法分析:https://blog.csdn.net/weixin_46635575/article/details/120887010
- 001冒泡排序:https://blog.csdn.net/weixin_46635575/article/details/120912718
- 002选择排序:https://blog.csdn.net/weixin_46635575/article/details/120924632
- 003插入排序:https://blog.csdn.net/weixin_46635575/article/details/120925291
- 004希尔排序:https://blog.csdn.net/weixin_46635575/article/details/120959617
- 005快速排序:https://blog.csdn.net/weixin_46635575/article/details/120966937
- 006归并排序:https://blog.csdn.net/weixin_46635575/article/details/120987410
- 007基数排序:https://blog.csdn.net/weixin_46635575/article/details/120992403
- 008堆排序:https://blog.csdn.net/weixin_46635575/article/details/121012144
一、基本介绍
1、基本介绍
- 基数排序(radix sort)属于“分配式排序”,又称为“桶子法”(bucket sort)或bin sort,顾名思义,它是通过键值的各个位的值,将要排序的元素分配致某些“桶”中,达到排序的作用。(说文字不太好理解,其实桶就是数组)
- 基数排序法属于稳定的排序,基数排序法是效率高的稳定排序算法
- 基数排序是桶排序的扩展
- 基数排序是1887年赫尔曼.何乐礼发明的,它是这样实现的:将整数按位数切割成不同的数字,然后按每个位数分别比较。
2、基本思想
- 将所有的待比较数值统一为同样的位数长度,数位较短的前面补0,然后从贵低位开始,依次进行排序,这样从低位排序一直到最高位排序完成以后,数列就变成一个有序序列。
3、来看一下图理解过程
-
第一轮:现在是对个位排序
-
第二轮:现在是对十位进行排序。
- 第三轮:是对百位排序 -
总共重复多少轮呢:在于你的数据的位数大小
二、代码实现
每一句话都好好理解,包括每一句注释都好好理解,不然你很可能看不懂
(1)推导版
public class RadixSort {
public static void main(String[] args) {
int[] arr = {53,3,542,748,14,214};
radixSort(arr);
System.out.println(Arrays.toString(arr));
}
//基数排序方法
public static void radixSort(int[] arr) {
//推导版
//先定义一个二维数组,代表10个桶,每一个桶就是一个一维数组
//你无法判断你数里面究竟有1,2,3,4,5,6,7,8,9,0呢,不确定大小,只能多定义一点,显然就是空间换时间的经典算法
int[][] bucket = new int[10][arr.length];
//为了记录每一个桶中实际存放了多少个数据,因为我们不能判断,我们定义一个一维数组来记录各个桶放入数据的个数
//bucketElementCounts[0]记录的就是bucket[0]的这个桶的数据个数
int[] bucketElementCounts = new int[10];
//第一轮,针对个位进行排序
//1、把数据放入到对应的桶中
for (int i = 0; i < arr.length; i++) {
//取出每个元素的个位
int digitOfELement = arr[i] % 10;
//然后放到对应的桶中
//bucketElementCounts[digitOfELement]这句话就得到了第多少个数据
bucket[digitOfELement][bucketElementCounts[digitOfELement]] = arr[i];
bucketElementCounts[digitOfELement] ++;//往后移动一个位置
}
//2、按照10个桶的顺序,把它取出放到原数组
int index = 0;//用来索引我们的arr数组
for (int i = 0; i < bucketElementCounts.length; i++) {
//如果桶中有数据,我们才放入到原数组里面
if (bucketElementCounts[i] != 0) {//说明对应的第k个桶有数据
//循环第k个一维数组,放入原数组
for (int j = 0; j < bucketElementCounts[i]; j++) {
//取出元素放入arr
arr[index] = bucket[i][j];
index++;
}
}
//第一轮结束:要把我们的桶里面数据置零
bucketElementCounts[i] = 0;
}
//第二轮的处理
System.out.println("------------------------------------");
//1、这个过程不用变化,除了一个%10
for (int i = 0; i < arr.length; i++) {
//取出每个元素的十位
int digitOfELement = (arr[i] / 10) % 10;
//然后放到对应的桶中
//bucketElementCounts[digitOfELement]这句话就得到了第多少个数据
bucket[digitOfELement][bucketElementCounts[digitOfELement]] = arr[i];
bucketElementCounts[digitOfELement] ++;//往后移动一个位置
}
//2、放数据不变化
index = 0;//用来索引我们的arr数组
for (int i = 0; i < bucketElementCounts.length; i++) {
//如果桶中有数据,我们才放入到原数组里面
if (bucketElementCounts[i] != 0) {//说明对应的第k个桶有数据
//循环第k个一维数组,放入原数组
for (int j = 0; j < bucketElementCounts[i]; j++) {
//取出元素放入arr
arr[index] = bucket[i][j];
index++;
}
}
//同样的道理
bucketElementCounts[i] = 0;
}
//第三轮
for (int i = 0; i < arr.length; i++) {
//取出每个元素的百位
int digitOfELement = (arr[i] / 100) % 10;
//然后放到对应的桶中
//bucketElementCounts[digitOfELement]这句话就得到了第多少个数据
bucket[digitOfELement][bucketElementCounts[digitOfELement]] = arr[i];
bucketElementCounts[digitOfELement] ++;//往后移动一个位置
}
//2、放数据完全不用变化
index = 0;//用来索引我们的arr数组
for (int i = 0; i < bucketElementCounts.length; i++) {
//如果桶中有数据,我们才放入到原数组里面
if (bucketElementCounts[i] != 0) {//说明对应的第k个桶有数据
//循环第k个一维数组,放入原数组
for (int j = 0; j < bucketElementCounts[i]; j++) {
//取出元素放入arr
arr[index] = bucket[i][j];
index++;
}
}
//同样的道理
bucketElementCounts[i] = 0;
}
}
}
(2)总体实现版
package cn.mldn;
import java.util.Arrays;
public class RadixSort {
public static void main(String[] args) {
int[] arr = {53,3,542,748,14,214};
radixSort(arr);
System.out.println(Arrays.toString(arr));
}
//基数排序方法
public static void radixSort(int[] arr) {
int[][] bucket = new int[10][arr.length];
int[] bucketElementCounts = new int[10];
//总体版
//总的来说就要关心的是最大的位数,然后就没什么事了
//所有我们要通过求解得到最大值,来判断到底要循环多少次
//得到最大的数
int max = arr[0];//假设最大值为arr[0]
for (int i = 0; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
//得到最大的位数,这个也很巧妙的
int maxLength = (max + "").length();
//这个n设置得很巧妙哦,一定以后要有这种思想,我们看看总体要实现多少次循环
for (int y = 0, n = 1; y < maxLength; y++ , n = n * 10) {
//1、把数据放入到对应的桶中
for (int i = 0; i < arr.length; i++) {
//取出每个元素的个位
int digitOfELement = (arr[i] / n) % 10;
//然后放到对应的桶中
//bucketElementCounts[digitOfELement]这句话就得到了第多少个数据
bucket[digitOfELement][bucketElementCounts[digitOfELement]] = arr[i];
bucketElementCounts[digitOfELement] ++;//往后移动一个位置
}
//2、按照10个桶的顺序,把它取出放到原数组
int index = 0;//用来索引我们的arr数组
for (int i = 0; i < bucketElementCounts.length; i++) {
//如果桶中有数据,我们才放入到原数组里面
if (bucketElementCounts[i] != 0) {//说明对应的第k个桶有数据
//循环第k个一维数组,放入原数组
for (int j = 0; j < bucketElementCounts[i]; j++) {
//取出元素放入arr
arr[index] = bucket[i][j];
index++;
}
}
bucketElementCounts[i] = 0;
}
}
}
}
(3)性能测试
看清楚啊,这里是八十万个数据哦,看性能都很高。比我们的快速排序都高,也一秒都用不了就OK了
package cn.mldn;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class RadixSort {
public static void main(String[] args) {
int[] arr = new int[800000];
for (int i = 0; i < 800000; i++) {
arr[i] = (int)(Math.random()*80000);//生成0到80000的数
}
//2、输出时间
Date date1 = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");//格式化
String date1Str = simpleDateFormat.format(date1);
System.out.println("排序前的时间" + date1Str);
radixSort(arr);
Date date2 = new Date();
String date2Str = simpleDateFormat.format(date2);
System.out.println("排序后的时间" + date2Str);
}
//基数排序方法
public static void radixSort(int[] arr) {
int[][] bucket = new int[10][arr.length];
int[] bucketElementCounts = new int[10];
//总体版
//总的来说就要关心的是最大的位数,然后就没什么事了
//所有我们要通过求解得到最大值,来判断到底要循环多少次
//得到最大的数
int max = arr[0];//假设最大值为arr[0]
for (int i = 0; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
//得到最大的位数,这个也很巧妙的
int maxLength = (max + "").length();
//这个n设置得很巧妙哦,一定以后要有这种思想,我们看看总体要实现多少次循环
for (int y = 0, n = 1; y < maxLength; y++ , n = n * 10) {
//1、把数据放入到对应的桶中
for (int i = 0; i < arr.length; i++) {
//取出每个元素的个位
int digitOfELement = (arr[i] / n) % 10;
//然后放到对应的桶中
//bucketElementCounts[digitOfELement]这句话就得到了第多少个数据
bucket[digitOfELement][bucketElementCounts[digitOfELement]] = arr[i];
bucketElementCounts[digitOfELement] ++;//往后移动一个位置
}
//2、按照10个桶的顺序,把它取出放到原数组
int index = 0;//用来索引我们的arr数组
for (int i = 0; i < bucketElementCounts.length; i++) {
//如果桶中有数据,我们才放入到原数组里面
if (bucketElementCounts[i] != 0) {//说明对应的第k个桶有数据
//循环第k个一维数组,放入原数组
for (int j = 0; j < bucketElementCounts[i]; j++) {
//取出元素放入arr
arr[index] = bucket[i][j];
index++;
}
}
bucketElementCounts[i] = 0;
}
}
}
}
(4)基数排序算法注意事项
基数排序是一个经典的空间换时间,你也可以测试一下,把我们的测试数据跳为八千万个数据,你的数据大了会浪费额外的内存,绝对会报错,除非你的内存很大,但是尽量不要太大。