前言
计数排序是一种非基于比较的排序方法,在某些特定的场景中,使用计数排序的方式可以实现O(n+k)的时间复杂(k表示待排序的数据范围),比任何基于比较的排序方法都要快。
算法分析
1、给每一个数都准备一个存放的空间,一般可以用数组来记录。
2、然后对待排序的数据进行遍历,记录每一个数出现的次数,并放在对应的数组下标中。
3、最后从数组中以此遍历出来即可。
图解分析
假设原始待排序数据为:6,3,7,5,3,2,5
构建一个计数数组,大小等于原始数组取值的范围,假设待排序数据都是正整数,那么对于上面的待排序数组的取值范围就是0~8
以此记录每个位置对应值出现的次数
最后以此遍历计数数组即可
代码实现
public class CountSort {
public static void main(String[] args) {
int[] arr = {
6, 3, 7, 5, 3, 2, 5};
count(arr);
System.out.println(Arrays.toString(arr));
}
private static void count(int[] arr) {
// 边界处理
if (arr == null || arr.length < 2) {
return;
}
int len = arr.length;
// 用来确定计数数组的范围
int max = Integer.MIN_VALUE;
for (int i = 0; i < len; i++) {
max = Math.max(max, arr[i]);
}
// 定义计数数组
int[] countArr = new int[max + 1];
// 统计每个值出现的次数,并放到计数数组对应的下标中
for (int i = 0; i < len; i++) {
countArr[arr[i]]++;
}
// 依次从计数数组中取出,并重新赋值给arr数组,便完成了排序
int i = 0;
for (int j = 0; j < len + 1; j++) {
while (countArr[j]-- > 0) {
arr[i++] = j;
}
}
}
}
计数排序的局限性
当然从计数排序的方法分析和代码实现上可以看出,计数排序是存在一定局限性的。
1、数据的范围不能太大,如果范围太大则计数数组也会变的很大,最后导致遍历计数数组的时间复杂度O(k),直接超过了一些基于比较排序方法的n*log(n)大小。
2、需要额外的内存空间,计数数组是通过空间换时间的代价来实现的。