一般遇到排序我们首先会想比较大小,比如冒泡排序, 插入排序, 合并排序, 快速排序等.排序过程都需要去对比,寻找参照物然后确定顺序位置.
这时候如果有一个参照物,它本身就是有序的,我们只要将对应的元素放置进去,那么完全放置进去后呈现的就是排序好的.
1.计数排序是利用数组下标作为参照物确定元素位置
2.运用下标作为参照即参与排序的元素可以变成数组下标,那么就要求被排元素必须是整数
1.有一组整数序列 A,找到A中的最大值 max
2.新建累计数组B, B.length 为 max+1 ,这样的话B的最后一个元素下标为max
3.数组B值以0填充,开始计数, A中元素出现一次, 对应的B位置值加一,计算下标值在A中出现的频次
4.把B中每个元素与之前元素进行累加,表示已占用空间,奇妙发生在此,当前占用空间-1即是元素排序后存在的下标位置,然后自身计数-1,因为会有重复数据
4.新建写回数组C, 长度与A一致, 把在B中排序完成集合写回C
原生数组A
6 | 2 | 2 | 4 | 3 | 3 | 5 | 1 |
新建数组B, 取A中最大值6加上一为B长度,以零填充
0 | 1 | 2 | 3 | 4 | 5 | 6 |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
数组B对A中的值进行计数
0 | 1 | 2 | 3 | 4 | 5 | 6 |
0 | 1 | 2 | 2 | 1 | 1 | 1 |
B数组元素进行累加,表示已占用位置
0 | 1 | 2 | 3 | 4 | 5 | 6 |
0 | 1 | 3 | 5 | 6 | 7 | 8 |
新建数组C 用于回写排序元素,长度与A一致.
我们先分析几个便于理解
以上是根据B的下标顺序来分析的,回写我们需要根据A中元素,A中第一个为6,在B中对应下标6,值为8,表示已占据8个空间,回写C[8-1] = 6
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
1(8) | 2(3) | 2(2) | 3(6) | 3(5) | 4(4) | 5(7) | 6(1) |
注释:值后小括号表示回写顺序
function counting_sort(A){
const max = Math.max(...A)
let B = Array.from({length:max+1}).fill(0); //创建累计数组,并填充0
let C = new Array(); //创建回写数组
A.forEach( (_,i) => B[A[i]]++) //累计数组频次计算
for(let i=1; i