计数排序是先统计原数组中每个数字出现的次数,然后再根据这些统计构建结果数组。
统计时是使用一个辅助数组,将原数组中的数字作为辅助数组的下标,将数字出现的次数作为值。
计数排序的优点是:
- 线性复杂度
缺点是:
- 数字的大小范围受限
- 额外的空间,如果数字范围比较大,空间消耗也会变大
所以适合使用计数排序的场景是:
- 数字都是整数,而且数字范围比较小
- 需要实现线性复杂度时
- 时间复杂度:$O(n+k)$,n 是排序数组的长度,k 是排序数组中数字的范围,也就是最大的数字。一共有 4 层循环,找最大数字以及计算每个数字出现次数的时间复杂度是
$O(n)$ ;生成结果数组时,遍历辅助数组countArr
的时间是$O(k)$ ,在遍历countArr
内部还有一个while
循环,那个加起来也是$O(n)$ ,所以总的时间复杂度是$O(3n+k)$ ,也就是$O(n+k)$ 。 - 空间复杂度:$O(n+k)$,n 是结果数组的长度,k 是辅助计数数组的长度。
JavaScript Code
function countingSort(array) {
const maxNum = Math.max(...array);
const countArr = Array(maxNum + 1).fill(0);
array.forEach(n => countArr[n]++);
const resArr = Array(array.length);
let index = 0;
countArr.forEach((count, num) => {
while (count > 0) {
resArr[index++] = num;
count--;
}
});
return resArr;
}