基数排序
第一步:将数组中的最大值找出来并记录
第二步:确定最大值是几位数并记录
第三步:利用位数从右到左放入桶里(即个、十、百、千~)
第四步:将桶里的值依次拿出覆盖到原先数组里面
例如:3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48
看个位数:(代码里面取模后算出怕是单位负数最小值负9,所以统一全部加10)
3 | 44 | 38 | 5 | 47 | 15 | 36 | 26 | 27 | 2 | 46 | 4 | 19 | 50 | 48 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
13 | 14 | 18 | 15 | 17 | 15 | 16 | 16 | 17 | 12 | 16 | 14 | 19 | 10 | 18 |
放入对应桶里:
10 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
---|---|---|---|---|---|---|---|---|
50 | 2 | 3 | 44,4 | 5,15 | 36,26,46 | 47,27 | 38,48 | 19 |
然后依次取出:
50, 2, 3, 44, 4, 5, 15, 36, 26, 46, 47, 27, 38, 48, 19
看十位数:(代码里面取模后算出怕是单位负数最小值负9,所以统一全部加10)
50 | 2 | 3 | 44 | 4 | 5 | 15 | 36 | 26 | 46 | 47 | 27 | 38 | 48 | 19 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
15 | 10 | 10 | 14 | 10 | 10 | 10 | 13 | 12 | 14 | 14 | 12 | 13 | 14 | 11 |
放入对应桶里:
10 | 11 | 12 | 13 | 14 | 15 |
---|---|---|---|---|---|
2,3,4,5 | 15,19 | 26,27 | 36,38 | 44,46,47,48 | 50 |
然后依次取出:
2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50
public class RadixSortTest {
public static void main(String[] args) {
int[] arr = {3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48};
int maxDigit = getMaxDigit(arr);
int[] sort = radixSort(arr, maxDigit);
System.out.println(Arrays.toString(sort));
}
// 获取最大值的位数
public static int getMaxDigit(int[] arr) {
int maxValue = getMaxValue(arr);
return getNumLength(maxValue);
}
// 获取数组里的最大值
public static int getMaxValue(int[] arr) {
int maxValue = arr[0];
for (int value : arr) {
if (maxValue < value) {
maxValue = value;
}
}
return maxValue;
}
// 求位数,例如 10 是两位,100 是三位
public static int getNumLength(long num) {
if (num == 0) {
return 1;
}
int length = 0;
for (long temp = num; temp != 0; temp /= 10) {
length++;
}
return length;
}
public static int[] radixSort(int[] arr, int maxDigit) {
int mod = 10;
int dev = 1;
for (int i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
// int[][] counter = new int[mod * 2][0];
// 考虑负数的情况,这里扩展一倍队列数,其中 [0-9]对应负数,[10-19]对应正数 (bucket + 10)
// 创建了20个桶(行数),每个桶暂时没有元素
int[][] counter = new int[20][0];
for (int j = 0; j < arr.length; j++) {
// int bucket = ((arr[j] % mod) / dev) + mod;
// mod 换为 10 保证了如果是负数位数为 9,bucket 能保证大于 0
int bucket = ((arr[j] % mod) / dev) + 10;
// 外循环第一次 mod = 10, dev = 1:
// 3 44 38 5 47 15 36 26 27 2 46 4 19 50 48
// 13 14 18 15 17 15 16 16 17 12 16 14 19 10 18
// 外循环第二次 mod = 100, dev = 10:
// 50 2 3 44 4 5 15 36 26 46 47 27 38 48 19
// 15 10 10 14 10 10 11 13 12 14 14 12 13 14 11
// 每次循环数据对应桶进行插入(桶原先是没有元素,先扩容后插入)
counter[bucket] = arrayAppend(counter[bucket], arr[j]);
// 外循环第一次后桶:
// 10:50
// 12:2
// 13:3
// 14:44 4
// 15:5 15
// 16:36 26 46
// 17:47 27
// 18:38 48
// 19:19
// 外循环第二次后桶:
// 10:2 3 4 5
// 11:15 19
// 12:26 27
// 13:36 38
// 14:44 46 47 48
// 15:50
}
int pos = 0;
// 第一次外循环后数组变成:50 2 3 44 4 5 15 36 26 46 47 27 38 48 19
// 第二次外循环后数组变成:2 3 4 5 15 19 26 27 36 38 44 46 47 48 50
for (int[] bucket : counter) {
for (int value : bucket) {
arr[pos++] = value;
}
}
}
return arr;
}
// 自动扩容,并保存数据
public static int[] arrayAppend(int[] arr, int value) {
arr = Arrays.copyOf(arr, arr.length + 1);
arr[arr.length - 1] = value;
return arr;
}
}
参考:基数排序动图演示及代码