本章知识点:
- 比较器(重载运算符)
- 计数排序
- 基数排序
Part 1 : 比较器
什么是比较器(以Java为例子)
比较器是一个这样的函数:
- 参数是两个待比较的对象
- 函数返回负数的时候,表示第一个参数排在前面。
- 函数返回正数的时候,表示第二个参数排在前面。
(有一些特定的数据结构或者方法就要求提供比较器:sort方法之类的)
比较器的使用:
- 比较器的本质是重载运算符
- 可以应用在特殊的排序上(自定义的排序) or 根据特殊标准的排序(只按照对象中的一个数值进行排序)
实现改进:作差法直接起飞了
public static int comparator(object A, object B) {
return A - B;
}
Part 2 : 不基于比较的排序 桶排序
像这类不基于比较的排序多多少少都是和数据情况有关。
基于比较的排序只需要比较规则,所以使用范围很广。而不基于比较的排序因为需要额外信息所以适用范围就相对小。
不基于比较但是基于分类
计数排序
- 初始化max
- 找到数组中的最大数字作为max
- 创建max个桶
- 遍历数组,把数据放进桶里面
- 把桶里面的数据还原成数组
//很easy的codeing,没有技术含量
public static void countSort(int[] arr) {
if(arr == null || arr.length < 2) {
return;
}
int max = Integer.MIN_VALUE;
for(int i = 0; i < arr.length; i++) {
max = Math.max(max,arr[i]);
}
//创建桶
int[] bucket = new int[max+1];
//入桶
for(int i = 0; i < arr.length; i++) {
bucket[arr[i]]++;
}
//桶中数据还原成数组
int i = 0;
for(int j = 0; j < bucket.length; j++) {
while (bucket[j]-- > 0){
arr[i++] = j;
}
}
}
就是用桶来分类统计然后还原回去就好了。
基数排序
计数统计有几个数就要用几个桶,太浪费空间了!
基数统计稍微高级一点,但是要求被统计的数字要有“进制规则”或者说是优先级。
这里的桶是队列,先入桶的要先出桶。
桶的顺序是从大到小。
这里使用队列来优化空间了,只使用一个count数组就解决出桶入桶的问题,没有能进制个桶:
//要用到的子操作
// 1.返回数组中最大数的位数
public static int maxbits(int[] arr) {
//或许可以使用堆来快速找到最大值?没有加速 都是O(n)
int max = Integer.MIN_VALUE;
for(int i = 0; i < arr.length; i++) {
max = Math.max(max, arr[i]);
}
int res = 0;
while(max != 0) {
max /= 10;
res++;
}
return res;
}
// 2.返回数字k的第d个数字
public static int getDigit(int x, int d) {
//别想着循环一个个除了^^
//x / ((int) Math.pow(10, d - 1))去掉从个位(1位)到d-1位的数字
//在取个位数的模
return ((x / ((int) Math.pow(10, d - 1))) % 10);
}
//桶排序
//程序入口
public static void radixSort(int[] arr) {
if(arr == null || arr.length < 2) {
return;
}
radixSort(arr,0,arr.length - 1, maxbits(arr));
}
public static void radixSort(int[] arr, int begin, int end,int digit) {
final int raidx = 10;
int i = 0, j = 0;
//中间数组,用来存放出桶之后的数据
int[] bucket = new int[end - begin + 1];
//开始桶排序
for(int d = 1; d <= digit; d++) {
int[] count = new int [raidx];
//入桶
//1. 统计第d位数字为i的数字个数
for(i = begin; i <= end; i++) {
j = getDigit(arr[i],d);
count[j]++;
}
//2. 累加个数得到第d位数字小于等于i的数字个数
for(i = 1; i < raidx; i++){
count[i] = count[i] + count[i - 1];
}
//出桶
for(i = end ;i >= begin; i--) {
j = getDigit(arr[i],d);
bucket[count[j] - 1] = arr[i];
count[j]--;
}
//写回原数组
for(i = begin, j = 0; i <= end ; i++, j++){
arr[i] = bucket[j];
}
}
}