计数排序

83 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情

前言

提起排序算法那真是太多了,什么插入排序、快排、冒泡排序、堆排序等等,今天新了解了一种排序感觉还挺有意思的,那就是技术排序。

计数排序的核心

  • 计数排序的核心就用一个新的数组来记录目标数组,通过一定的转换来实现排序
  • 首先初始化一个中间数组,用来存储目标数组,这里目标数组的长度要设置成为目标数组的长度+1
  • 中间数组的下标是目标数组的项,比如说目标数组中有两个2,两个3,那到中间数组中的表现形式就是在下标为2的地方值为2,下标为3的地方值为3 如下代码:
var hIndex = function (citations) {
            let result = 0
            let barrels = new Array(Math.max(...citations) + 1).fill(0)
            //把数据插入计数数组
            for (let i = 0; i < citations.length; i++) {
                  barrels[citations[i]]++
            }
            //这里是还原排序后的原来数组
            let newIndex = 0
            for (let j = 0; j<barrels.length; j++) {
                //可能有重复的数字
                while(barrels[j]>0){
                    citations[newIndex++] = j
                    barrels[j]--
                }
            }
            return citations
        };
        console.log(hIndex([3,0,6,5,1]))

运行结果如下:

image.png

优化代码

1.上面的代码生成的中间数组的长度是最大值+1,试想一下如果目标数组是从200开始的,那前200个常熟是不是就浪费了?

2.如果数组中有负数怎么办?

基于上上面的两点可以把代码改为如下格式

function countingSort(nums) {
            let max = Math.max(...nums); // 找到这个数组的 最大 最小值
            let min = Math.min(...nums);
            //创建计数数组,这里计数数组的长度改为了max-min+1,这样就会解决上面所说的问题1
            let count = new Array(max - min + 1).fill(0)
            for (let i = 0; i < nums.length; i++) {
                // index + min = value
                //这里的计数数组的下标不再是目标数组的项,而是用nums[i]-min来表示,这样不管是正数还是负数都可以在计数数组中标记出来
                let index = nums[i] - min
                count[index]++;
            }

            // 还原原数组
            let sortedIndex = 0;
            for (let i = 0; i < count.length; i++) {
                while (count[i] > 0) {
                    nums[sortedIndex++] = i + min; // 关联关系为:index + min = value
                    count[i]--;
                }
            }
            return nums;
        }

结果如下:

image.png

总结

可以发现计数排序的实现很简单,并且时间复杂度也小,只有O(n),比其它所有的排序都低,但是不是你也和我一样以前没怎么听说过这个排序,这是因为它也有着很明显的缺点。那就是:

  • 计数排序正能排序整数,如果是小数就不行
  • 由于使用了新的数组,内存消耗比较大