概念:
计数排序不是一个比较排序算法,该算法于1954年由 Harold H. Seward提出,通过计数将时间复杂度降到了O(N),利用数组下标来缺的元素的正确位置
案例:
假设数组中有10个随机数,取值范围0~10,要求用最快的速度把这20个证书从小到大进行排序
考虑到这些整数只能够在 0、1、2、3、4、5、6、7、8、9、10 这11个数中取值,取值范围有限。所以,可以根据这有限的范围,建立一个长度为11的数组,数组下标从0-10,元素初始值全为0
假设10个随机数整数值如下
9,3,5,4,9,1,2,7,8,1
第一次计数
第二次计数
第三次计数
第四次计数
第五次计数
第六次计数
第七次计数
第八次计数
第九次计数
第十次计数
最终,当数列遍历完毕时,数组状态如下
该数组中每一个下标位置的值代表数列中对应整数出现的次数。
有了这个统计结果,排序就简单多了,直接便利数组,输出数组元素的下标值,元素的值时几,就输出几次
1,1,2,3,4,5,7,8,9,9
显然,现在输出的数列已经是有序的了。
这就是计数排序的基本过程,它适用于一定范围内的整数排序。在取值范围不是很大的情况下,它的性能甚至快过那些时间复杂度为 O(nlogn) 的排序。
# 代码实现:
public class test {
public static void main(String[] args) {
int[] array = new int[] {4,4,6,5,3,2,8,1,7,10};
int[] sortedArray = countSort(array);
System.out.println(Arrays.toString(sortedArray));
}
public static int[] countSort(int[] array){
//1. 得到数列最大值
int max = array[0];
for (int i = 1; i < array.length; i++) {
if(array[i] > max){
max = array[i];
}
}
//2. 根据数列最大值确定统计数组的长度
int[] countArray = new int[max+1];
for(int i=0; i<array.length; i++){
countArray[array[i]]++;
}
//遍历统计数组,输出结果
int index = 0;
int[] sortedArray = new int[array.length];
for(int i=0; i<countArray.length; i++){
for(int j=0; j<countArray[i]; j++){
sortedArray[index++] = i;
}
}
return sortedArray;
}
}
[1, 2, 3, 4, 4, 5, 6, 7, 8, 10]
这段代码在开头有一个步骤,就是求数列的最大整数值max。后面创建 的统计数组countArray,长度是max+1,以此来保证数组的最后一个下 标是max。
计数排序优缺点
- 当数列最大和最小值差距过大时,并不适合用计数排序
例如给出20个随机整数,范围在0到1亿之间,这时如果使用计数排序,需要创建长度为1亿的数组,不但浪费空间,而且时间复杂度也会随之升高
- 当数列元素不是整数时,也不适合用计数排序
如果数列中的元素都是小数,如25.213,或0.00 000 001 这样的数字,则无法创建对应统计数组,这样显然无法进行计数排序。
对于这些局限性,另一种线性时间排序算法做出弥补、这周排序算法叫做桶排序
个人博客地址:http://blog.yanxiaolong.cn | 『纵有疾风起,人生不言弃』