基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成0-9的数字,然后按每个位的数分别进行桶排序。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。
基数排序具体步骤如下:
1、确定最大数的位数(考虑负数);
2、按位循环进行桶排序。
注:桶排序参考上篇文章;由于每位仅有0-9是个数,考虑负数情况,桶的数量固定为20,0-9号桶放负数,10-19号桶放不小于0的数。
LSD 基数排序动图演示
执行过程请移步文章末尾:执行过程。
基数排序分为两种方式:LSD(最低位优先(Least Significant Digit first)法)、MSD(最高位优先(Most Significant Digit first)法)。
LSD的基数排序适用于位数小的数列,如果位数多的话,使用MSD的效率会比较好。MSD的方式与LSD相反,是由高位数为基底开始进行分配,但在分配之后并不马上合并回一个数组中,而是在每个“桶子”中建立“子桶”,将每个桶子中的数值按照下一数位的值分配到“子桶”中。在进行完最低位数的分配后再合并回单一的数组中。
LSD代码实现:
package com.algorithm.sort;
import java.util.Arrays;
/**
* @author LuoFei
* @className: RadixSort
* @projectName algorithm
* @description: TODO
* @date 2023/3/3 14:53
*/
public class RadixSort {
public static void radixSort(int[] arr) {
System.out.println("获取数组最大数的位数,确定进行几遍桶排序(考虑负数)");
int maxDigit = getMaxDigit(arr);
System.out.println("位数为:"+maxDigit);
sort(arr, maxDigit);
}
public static int getMaxDigit(int[] arr) {
int maxValue = getMaxValue(arr);
return getNumLength(maxValue);
}
public static int getMaxValue(int[] arr) {
int maxValue = Math.abs(arr[0]);
for (int value : arr) {
if (maxValue < Math.abs(value)) {
maxValue = Math.abs(value);
}
}
return maxValue;
}
public static int getNumLength(int value) {
int num = 0;
if (value == 0) {
return 1;
}
int temp = value;
while (temp > 0) {
temp /= 10;
num++;
}
return num;
}
public static void sort(int[] arr, int maxDigit) {
System.out.println("开始排序");
System.out.println("通过对数值取余、求商,计算数值每位的十进制数,对每位的十进制数做桶排序。");
System.out.println("因为是十进制及考虑负数情况,桶的数量定为20,0-9号桶放负数,10-19号桶放不小于0的数");
int mod = 10;
int dev = 1;
System.out.println("定义初始取余基数为:"+mod+", 初始初始为:"+dev);
for (int i = 0;i<maxDigit;i++,mod*=10,dev*=10) {
System.out.println("第"+(i+1)+"位开始桶排序");
int[][] buckets = new int[20][0];
for(int j=0;j<arr.length;j++) {
int index = (arr[j]%mod)/dev + 10;
buckets[index] = arrAppend(buckets[index], arr[j]);
}
int index = 0;
for (int[] bucket : buckets) {
for (int k = 0;k<bucket.length;k++) {
arr[index++] = bucket[k];
}
}
System.out.println("第"+(i+1)+"位桶排序后数组位:"+Arrays.toString(arr));
}
}
public static int[] arrAppend(int[] bucket, int value) {
bucket = Arrays.copyOf(bucket, bucket.length+1);
bucket[bucket.length-1] = value;
return bucket;
}
public static void main(String[] args) {
int[] arr = {65, -122, -58, 30, -19, 21, 2, 34, 42, 7, 2, 0};
System.out.println("基数排序");
System.out.println("初始数组:"+ Arrays.toString(arr));
System.out.println("==============开始基数排序===============");
radixSort(arr);
System.out.println("==============基数排序完成===============");
System.out.println("最终数组"+Arrays.toString(arr));
}
}
执行过程:
基数排序
初始数组:[65, -122, -58, 30, -19, 21, 2, 34, 42, 7, 2, 0]
==============开始基数排序===============
获取数组最大数的位数,确定进行几遍桶排序(考虑负数)
位数为:3
开始排序
通过对数值取余、求商,计算数值每位的十进制数,对每位的十进制数做桶排序。
因为是十进制及考虑负数情况,桶的数量定为20,0-9号桶放负数,10-19号桶放不小于0的数
定义初始取余基数为:10, 初始初始为:1
第1位开始桶排序
第1位桶排序后数组位:[-19, -58, -122, 30, 0, 21, 2, 42, 2, 34, 65, 7]
第2位开始桶排序
第2位桶排序后数组位:[-58, -122, -19, 0, 2, 2, 7, 21, 30, 34, 42, 65]
第3位开始桶排序
第3位桶排序后数组位:[-122, -58, -19, 0, 2, 2, 7, 21, 30, 34, 42, 65]
==============基数排序完成===============
最终数组[-122, -58, -19, 0, 2, 2, 7, 21, 30, 34, 42, 65]