思路:
空间换时间 非比较排序
- 先统计,再遍历输出
- 求出待排序数组最大值与最小值的差值,加1作为统计数组的长度
- 遍历原数组,进行统计,例:原数组值为2,将countArr位置的value加1(初始value=0)
- 遍历统计数组,按照下标值输出,例:index:5 value:3 ,输出三次5
按照上述方法进行的计数排序,是不稳定的排序,优化思路:
求出统计数组下标值在排序后数组具备稳定性的位置
比如1,2,1,第三个1在排序后数组的位置是在第二的位置,我们在排序中不能改变第一个1和第三个1的位置
具体方法: 统计数组从第二个元素开始,每一个元素都加上前面所有元素之和
这句话有点难理解
例:1 2 1 三个数,统计数组:0 2 1, 2 是第2个数,在最终排序中应该排名位置是第3,所以统计数组将前面三个value相加,0+2+1 = 3, 统计数组变成0 2 3,同理统计数组其它value也是从开始value到当前value之和,这个和代表当前统计数组下标在排序后数组中的排名
在逆序遍历时,每输出一个元素,统计数组对应value–(好难描述)
具体实现思路:
- 统计数组A中每个值A[i]出现的次数,存入C[A[i]]
- 从前向后,使数组C中的每个值等于其与前一项相加,这样数组C[A[i]]就变成了代表数组A中小于等于A[i]的元素个数
- 反向填充输出数组B:将数组元素A[i]放在数组B的第C[A[i]]个位置(下标为C[A[i]] – 1),每放一个元素就将C[A[i]]递减
代码:
public class CountSort {
public static int[] countSort(int[] arr) {
int max = arr[0];
int min = arr[0];
//求原数组max,min
for(int i = 1; i < arr.length; i++) {
if(arr[i] > max) {
max = arr[i];
}
if(arr[i] < min) {
min = arr[i];
}
}
int d = max - min;
//创建统计数组
int[] countArr = new int[d+1];
for (int i = 0; i < arr.length; i++) {
//统计原数组值的个数
countArr[arr[i] - min]++;
}
int sum = 0;
for(int i = 0; i < countArr.length; i++) {
//求出逆序遍历时元素在统计数组的排名(index+1)
sum += countArr[i];
countArr[i] = sum;
}
int[] sortArr = new int[arr.length];
//逆序遍历
for(int i = arr.length -1; i >= 0; i--) {
//将原数组value放入输出数组指定位置
sortArr[countArr[arr[i]- min] - 1] = arr[i];
countArr[arr[i] - min]--;
}
return sortArr;
}
public static void main(String[] args) {
int[] arr = new int[] {95, 94, 91, 98, 99, 90, 99, 93, 92, 91};
int[] sortArr = countSort(arr);
System.out.println(Arrays.toString(sortArr));
}
}
计数排序缺点:
- 当数列最大最小值差距过大时,并不适用计数排序,浪费空间
- 当数列元素不是整数,并不适用计数排序