目录
1、什么是基数排序?
基数排序是桶排序的扩展,也是一种非比较排序。桶排序适用于数据分布比较均匀的情况,如果数据分布不是很均匀,并且数据中存在几个极大值,这会导致桶排序存在很多的空桶,这会造成内存的浪费,桶排序使用的是序列中元素的范围,基数排序使用的是序列中元素的位数,基数排序由于位数的范围是10位或者26位,所以可以避免创建过多的桶。基数排序将数据划分为一个个的关键字,其对相同数位上的关键字进行计数排序,如果位数不够则前面补0,从低位到高位进行排序,如果字符串比较可以从左到右比较。
2、基数排序的应用场景
基数排序适用于大范围的整数排序和字符串排序。
3、基数排序的思想
基数排序整体来看是一种“分配和收集”排序,其将序列中的元素按照位数进行划分,不够的补0,将相同位数的元素先分配,分配后相同位数的元素排好序后,进行收集,重复该操作,可以完成排序。也可以这样理解,基数排序使用的是一种分治思想,对序列中相同位数的元素进行计数排序,所有的位数循环完成,则排序完成。
4、基数排序的步骤
- 获取序列中的最大值,获取其长度length
- 新建一个二维数组用于模拟桶存放数据,取临时变量temp=1
- 循环的次数为length,新建数组count,用于保存各个桶中元素的个数,遍历原序列,序列中的元素先除以temp,再对10取余则可以得到,元素中个位数的值,将其放入各自编号的桶中,遍历结束,遍历count将排完序的数据放入到原数组中正确的位置,以此类推获取百位数,千位数,直到length循环结束。
5、代码实现
package com.kgf.algorithm.sort;
/***
* 基数排序
*/
public class RadixSorte {
public static void main(String[] args) {
int[] nums = {1, 4, 9, 2, 5, 3, 7, 6, 22, 23, 15, 24, 0, 3,
4, 5, 2, 3, 5, 12, 1, 3, 4, 2, 1,
3, 45, 1, 1};
RadixSorte rs = new RadixSorte();
rs.radixSort(nums);
for (int num : nums) {
System.out.print(num+"\t");
}
System.out.println();
}
/***
* @param nums
*/
public void radixSort(int[] nums){
//首先获取序列中的最大和最小值
int max = nums[0];
for (int i = 0; i < nums.length; i++) {
if (max<nums[i]){
max = nums[i];
}
}
String maxStr = max+"";
//创建二维数组
int[][] temp = new int[10][nums.length];
int temp1 = 1;
for (int i = 0; i < maxStr.length(); i++) {
//计算到哪个桶中
int[] countArr = new int[10];
for (int j = 0; j < nums.length; j++) {
int targetRadix = (nums[j]/temp1) % 10;
temp[targetRadix][countArr[targetRadix]] = nums[j];
countArr[targetRadix]++;
}
temp1 = temp1*10;
//开始调整数组中元素的位置
int sum = 0;
for (int j = 0; j < countArr.length; j++) {
for (int k = 0; k < countArr[j]; k++) {
nums[sum++] = temp[j][k];
}
}
}
}
}
6、基数排序的总结
基数排序的时间复杂度是O(k(n+d)),空间复杂度为O(dn),是稳定性算法。(k是位数,n是序列的长度,d是桶的个数)
基数排序的时间复杂度是O(k(n+d)):根据上面的代码可以推出时间复杂度为n+k(n+d),所以时间复杂度为O(k(n+d))
空间复杂度为O(dn):创建一个二维数组和一个记录个数,所以空间复杂度为O(dn)
是稳定性算法:相同的元素在同一个桶里面,按照原来的顺序排列,所以是稳定性算法。
7、基数排序的类比
基数排序主要是“分配和收集”,类似于:老师想将学生的成绩从小到大排序,则每月考一次试,难度越来越大,每次考完都进行一次排名。