题目
分析
在实际的比赛过程中很少会自己手写排序,顶多是定义一下排序规则。之所以要练习一下基数排序,是因为在后续学习过程中学到后缀数组时需要自己手写基数排序,那么这里使用的方法也和后缀数组一致,理解这里也便于后缀数组的学习。
桶排序全流程回顾
原数组:12 34 26 123 14 7
- 根据第一关键字即个位数放桶
2号桶:12
3号桶:123
4号桶:34 14
6号桶:26
7号桶:7 - 根据关键字实现一轮排序
12 123 34 14 26 7 - 根据第二关键字即十位数放桶
0号桶:7
1号桶:12 14
2号桶:123 26
3号桶:34 - 根据关键字实现一轮排序
7 12 14 123 26 34 - 根据第三关键字即百位数放桶
0号桶:7 12 14 26 34
1号桶:123 - 根据关键字实现一轮排序
7 12 14 26 34 123
经过三轮排序后,原数组有序。
基数排序过程详细分析
标记每个数字属于哪个桶
直接通过数字对应的关键字表示就可以了,可以写一个get(x,k)函数,表示取出数字x的第k个关键字,代码如下
private static int get(int a,int k) {
int id = 1;
while(a>0) {
if(id == k) return a%10;
a/=10;
id++;
}
return 0;
}
统计桶内存放的数字个数
count[get(a[j],i)]++;
2号桶(count=1):12
3号桶(count=1):123
4号桶(count=2):34 14
6号桶(count=1):26
7号桶(count=1):7
计算count的前缀和数组
count[j] += count[j-1];
2号桶(累积count=1):12
3号桶(累积count=2):123
4号桶(累积count=4):34 14
6号桶(累积count=5):26
7号桶(累积count=6):7
根据前缀和统计本轮排序后每个数字的位序
bu[count[get(a[j], i)]–] = a[j];
2号桶(累积count[2]=1):12
3号桶(累积count[3]=2):123
4号桶(累积count[4]=4):34 14
6号桶(累积count[6]=5):26
7号桶(累积count[7]=6):7
数字7的位序位累积count=6
数字26的位序位累积count=5
数字14的位序位累积count=4 count- -=3
数字34的位序位累积count=3
数字123的位序位累积count=2
数字12的位序位累积count=1
一轮排序后的结果为:
12 123 34 14 26 7
完整代码
import java.util.Arrays;
import java.util.Scanner;
public class 基数排序{
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int a[] = new int[n+1];
int maxV = 0,max = 0;
for (int i = 1; i <= n; i++) {
a[i] = scanner.nextInt();
maxV = Math.max(maxV, a[i]);
}
int count[] = new int[10];
int bu[] = new int[n+1];
while(maxV > 0) {
maxV /= 10;
max++;
}
for(int i = 1;i <= max;i++) {
Arrays.fill(count, 0);
for (int j = 1; j <= n; j++) count[get(a[j],i)]++;
for (int j = 1; j <= 9; j++) count[j] += count[j-1];
for (int j = n; j > 0; j--) {
int k = get(a[j], i);
bu[count[k]--] = a[j];
}
for (int j = 1; j <= n; j++) a[j]=bu[j];
}
for (int i = 1; i <= n; i++)
System.out.print(a[i] + " ");
}
private static int get(int a,int k) {
int id = 1;
while(a>0) {
if(id == k) return a%10;
a/=10;
id++;
}
return 0;
}
}