Counting Sort,适合少量的非负数排序。可实现优化以支持负数。
非比较排序。
由于用来计数的数组count的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。例如:计数排序是用来排序0到100之间的数字的最好的算法,但是它不适合按字母顺序排序人名。
算法步骤
- 找出待排序的数组中最大和最小的元素
- 统计数组中每个值为i的元素出现的次数,存入计数数组的第i项
- 对所有的计数累加
- 反向填充目标数组
复杂度
| 标题 | 数据 |
|---|---|
| 平均时间复杂度 | O(n+k) |
| 最好情况 | O(n+k) |
| 最坏情况 | O(n+k) |
| 空间复杂度 | O(k) |
| 排序方式 | Out-place |
| 稳定性 | 稳定 |
代码演示
function countingSort(list) {
let len = list.length;
if (len < 2) return list;
//设置最大最小默认值
let min = list[0],
max = list[0];
//通过循环比较,确定最大最小值
for (let i = 0; i < len; i++) {
if (list[i] > max) {
max = list[i]
} else if (list[i] < min) {
min = list[i]
}
}
//设置计数数组,数组空间为最大-最小+1,加少空间浪费
let count = new Array(max - min + 1)
//循环把计数的值放进计数数组中
for (let i = 0; i < len; i++) {
//元素-最小值得出计数数组的下标
let idx = list[i] - min;
if (count[idx] > 0) {
count[idx]++ //说明该下标已经存在值,所以+
} else {
count[idx] = 1 //初始化该下标的值
}
}
//设置新书组,将计数数组的值放回,完成排序
let res = [];
for (let i = 0; i < count.length; i++) {
//说明此下标存在值
while (count[i] > 0) {
res = [...res, i + min];
count[i]--
}
}
return res
}