将给定数组使用计数排序,从小到大排序,输出排序后的数组
计数排序: 计数排序是一个非基于比较的排序算法。它的优势在于在对一定范围内的整数排序时,它的复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法。 当然这是一种牺牲空间换取时间的做法,而且当O(k)>O(nlog(n))的时候其效率反而不如基于比较的排序(基于比较的排序的时间复杂度在理论上的下限是O(nlog(n)), 如归并排序,堆排序)
技术排序非常类似于桶排序,其主要实现是: 遍历原数组中的元素,以原数组中的元素作为count
数组的索引,以原数组中的元素出现次数作为count
数组的元素值。遍历完成后,遍历count
数组,找出其中元素值大于0的元素,将其对应的索引作为元素值填充到result
数组中去,每处理一次,count
中的该元素值减1,直到该元素值不大于0,依次处理count
中剩下的元素
分析:
假设有给定数组 s = [3,2,6,4,5,3,7]
数组中每个元素可以看作一个球,数组中最大的元素是 7,那么就设置7个桶,(如果最大为100,那么就要设置100个桶,这是计数排序的缺点,牺牲空间,所以计数排序是牺牲空间换取时间的排序算法)
7个桶在代码中可以被抽象为元素数量为桶数量的数组,即长度为7的数组,桶内放置球的个数为每个数组的元素值,刚开始都是0,那么最初的模型应当是: counstList = [0,0,0,0,0,0,0]
将球遍历,根据球上的数字放入对应下标的桶中,例如: s[0] = 3 ,那么第一个球放入到第三个桶中。s[1] = 2,放入到第二个桶中
做到这里,可能会发现这样去考虑会有一些问题:
- 假设 s = [91,90,100] ,最大值是100,那么我们需要放置 100 个桶
- 假设 s 中包含负数, 例如 s[0] = -1, 那么他应该放到哪个桶??第 -1 个桶??
再深入一些思考会发现,假设 s = [91, 90, 100], 那么实际上我们紧紧是对 > 90 且 < 100 的数进行排序,90之前的桶根本用不上,也不会有一个球放进去(因为没有数据是 < 90 的)。所以最好的办法,第一个桶对应的应该是数组中最小的数,即第一个桶放入的数据应该是90,那么由此可以得出:
第一个桶 应当放入 90
第二个桶 应当放入 91
第三个桶 应当放入 92
第N个桶 应当放入 90 + N - 1 【即 min(最小值) + N - 1】
得到: 应当放入第 N 个桶的数据 = min + N - 1
由此可得: N = 放入的数据 - min + 1
这样一来负数的问题也解决了, 假设 s = [-1, 3,5] ,会有 s[0] = -1, 那么他应当放入 第【 -1 - (-1) + 1 】个,即 第 1 个桶中, s[1] = 3, 放入第 【 3 - (-1) + 1 】 即第 5个桶中 。。以此类推
总结:
假设数组中最小值 为 min, 最大值为 max, 遍历的数组单个元素值为 val
- 桶的长度应为 max - min + 1
- 球上的数字(val)应放入第 val - min + 1 个桶中
由此,可根据待排数组,得出下图:
过程:
- min = 2 , max = 7 设置 max - min + 1 = 7 - 2 + 1 = 6 个桶
2.根据 N = 放入的数据 - min + 1
-
s[0] = 3, N = 3 - 2 + 1, 放入第2个桶
-
s[1] = 2, N = 2 - 2 + 1, 放入第1个桶
-
s[2] = 6, N = 6 - 2 + 1, 放入第5个桶
-
s[3] = 4, N = 4 - 2 + 1, 放入第3个桶
-
s[4] = 5, N = 5 - 2 + 1, 放入第4个桶
-
s[5] = 3, N = 3 - 2 + 1, 放入第2个桶
-
s[6] = 7, N = 7 - 2 + 1, 放入第6个桶
最终得到:
最后将桶中的数据依次取出,得到的数组就是排序后的数组了
代码实现:
const f = () => {
let min = s[0]
let max = s[0]
// 找出最小, 最大值
for (let i = 1; i < s.length; i++) {
let num = s[i]
min = min > num ? num : min
max = max < num ? num : max
}
console.log({ min, max })
// 创建 max - min + 1 长度的数组
const countList = new Array(max - min + 1).fill(0)
s.forEach(num => {
countList[num - min] = countList[num - min] + 1
})
console.log(countList)
const res = []
countList.forEach((val, index) => {
while (val > 0) {
res.push(index + min)
val--
}
})
console.log(res)
}
const s = [3, 2, 6, 4, 5, 3, 7]
f(s)
输出结果:
[ 2, 3, 3, 4, 5, 6, 7 ]