侵权投诉

深入浅谈计数排序

算法与数据结构 2021-04-28 16:20 次阅读

计数排序虽然不是面试常考题目,但是计数排序的求统计数组步骤和最后元素归位思想是我们刷题时经常用到的,例如原地置换,使用数组模拟 hashmap 等,所以还是很有必要看一下的。

今天我们就一起来看看线性排序里的计数排序到底是怎么回事吧。

我们将镜头切到袁记菜馆

因为今年袁记菜馆的效益不错,所以袁厨就想给员工发些小福利,让小二根据员工工龄进行排序,但是菜馆共有 100000 名员工,菜馆开业 10 年,员工工龄从 0 - 10 不等。

看来这真是一个艰巨的任务啊。

当然我们可以借助之前说过的 归并排序 和 快速排序 解决,但是我们有没有其他更好的方法呢?

了解排序算法的老哥可能已经猜到今天写什么啦。是滴,我们今天来写写用空间换时间的线性排序。

说之前我们先来回顾一下之前的排序算法,最好的时间复杂度为 O(nlogn) ,且都基于元素之间的比较来进行排序。

我们来说一下非基于元素比较的排序算法,且时间复杂度为 O(n),时间复杂度是线性的,所以我们称其为线性排序算法。

其优势在于在对一定范围内的整数排序时,它的复杂度为Ο(n+k),此时的 k 则代表整数的范围。快于任何一种比较类排序算法,不过也是需要牺牲一些空间来换取时间。

下面我们先来看看什么是计数排序,这个计数的含义是什么?

我们假设某一分店共有 10 名员工,

工龄分别为 1,2,3,5,0,2,2,4,5,9

那么我们将其存在一个长度为 10 的数组里,,但是我们注意,我们数组此时存的并不是元素值,而是元素的个数。见下图

09f15c56-a7f9-11eb-9728-12bb97331649.png

注:此时我们这里统计次数的数组长度根据最大值来决定,上面的例子中最大值为 9 ,则长度为 9 + 1 = 10。暂且先这样理解,后面会对其优化 。

我们继续以上图的例子来说明,在该数组中,索引代表的为元素值(也就是上面例子中的工龄),数组的值代表的则是元素个数(也就是不同工龄出现的次数)。

即工龄为 0 的员工有 1 个, 工龄为 1 的员工有 1 个,工龄为 2 的员工有 3 个 。。。

然后我们根据出现次数将其依次取出看看是什么效果。

0,1,2,2,2,3,4,5,5,9

我们发现此时元素则变成了有序的,但是这并不是排序,只是简单的按照统计数组的下标,输出了元素值,并没有真正的给原始数组进行排序。

这样操作之后我们不知道工龄属于哪个员工。

见下图

0a30bfea-a7f9-11eb-9728-12bb97331649.png

举例

虽然喵哥和杰哥工龄相同,如果我们按照上面的操作输出之后,我们不能知道工龄为 4 的两个员工,哪个是喵哥哪个是杰哥。

所以我们需要借助其他方法来对元素进行排序。

大家还记不记得我们之前说过的前缀和,下面我们通过上面统计次数的数组求出其前缀和数组。

0a4cf3d6-a7f9-11eb-9728-12bb97331649.png

因为我们是通过统计次数的数组得到了前缀和数组,那么我们来分析一下 presum 数组里面值的含义。

例如我们的 presum[2] = 5 ,代表的则是原数组小于等于 2 的值共有 5 个。presum[4] = 7 代表小于等于 4 的元素共有 7 个。

是不是感觉计数排序的含义要慢慢显现出来啦。

其实到这里我们已经可以理解的差不多了,还差最后一步,

此时我们要从后往前遍历原始数组,然后将遍历到的元素放到临时数组的合适位置,并修改 presum 数组的值,遍历结束后则达到了排序的目的。

这时有人要问了,为什么我们要从后往前遍历呢?

这个问题的答案,我们等下说,继续往下看吧。

0a583e94-a7f9-11eb-9728-12bb97331649.png

计数排序

我们从后往前遍历,nums[9] = 9,则我们拿该值去 presum 数组中查找,发现 presum[nums[9]] = presum[9] = 10 ,

大家还记得我们 presum 数组里面每个值的含义吗,我们此时 presum[9] = 10,则代表在数组中,小于等于的数共有 10 个,则我们要将他排在临时数组的第 10 个位置,也就是 temp[9] = 9。

我们还需要干什么呢?我们想一下,我们已经把 9 放入到 temp 数组里了,已经对其排好序了,那么我们的 presum 数组则不应该再统计他了,则将相应的位置减 1 即可,也就是 presum[9] = 10 - 1 = 9;

0a79d392-a7f9-11eb-9728-12bb97331649.png

下面我们继续遍历 5 ,然后同样执行上诉步骤

0aa1f8f4-a7f9-11eb-9728-12bb97331649.png

我们继续查询 presum 数组,发现 presum[5] = 9,则说明小于等于 5 的数共有 9 个,我们将其放入到 temp 数组的第 9 个位置,也就是

temp[8] = 5。然后再将 presum[5] 减 1 。

0aba5ae8-a7f9-11eb-9728-12bb97331649.png

是不是到这里就理解了计数排序的大致思路啦。

那么我们为什么需要从后往前遍历呢?我们思考一下,如果我们从前往后遍历,相同元素的话,前面的元素则会先归位再减一,这样则会使计数排序变成不稳定的排序算法。

这个排序的过程像不像查字典呢?通过查询 presum 数组,得出自己应该排在临时数组的第几位。然后再修改下字典,直到遍历结束。

那么我们先来用动画模拟一下我们这个 bug 版的计数排序,加深理解。

注:我们得到 presum 数组的过程在动画中省略。直接模拟排序过程。

计数排序

但是到现在就完了吗?显然没有,我们思考下这个情况。

假如我们的数字为 90,93,94,91,92 如果我们根据上面方法设置 presum 数组的长度,那我们则需要设置数组长度为 95(因为最大值是94),这样显然是不合理的,会浪费掉很多空间。

还有就是当我们需要对负数进行排序时同样会出现问题,因为我们求次数的时候是根据 nums[index] 的值来填充 presum 数组的,所以当 nums[index] 为负数时,填充 presum 数组时则会报错。

此时通过最大值来定义数组长度也不合理。

所以我们需要采取别的方法来定义数组长度。

下面我们来说一下偏移量的概念。

例如 90,93,94,91,92,我们 可以通过 max ,min 的值来设置数组长度即 94 - 90 + 1 = 5 。偏移量则为 min 值,也就是 90。那么我们的 90 则对应索引 0 。

见下图。

0afe7e08-a7f9-11eb-9728-12bb97331649.png

这样我们填充 presum 数组时就不会出现浪费空间的情况了,负数?出现负数的情况当然也可以。继续看

例如:-1,-3,0,2,1

0b08c994-a7f9-11eb-9728-12bb97331649.png

一样可以,哦了,到这里我们就搞定了计数排序,下面我们来看一哈代码吧。

class Solution {

public int[] sortArray(int[] nums) {

int len = nums.length;

if (nums.length 《 1) {

return nums;

}

//求出最大最小值

int max = nums[0];

int min = nums[0];

for (int x : nums) {

if (max 《 x) max = x;

if (min 》 x) min = x;

}

//设置 presum 数组长度,然后求出我们的前缀和数组,

//这里我们可以把求次数数组和前缀和数组用一个数组处理

int[] presum = new int[max-min+1];

for (int x : nums) {

presum[x-min]++;

}

for (int i = 1; i 《 presum.length; ++i) {

presum[i] = presum[i-1]+presum[i];

}

//临时数组

int[] temp = new int[len];

//遍历数组,开始排序,注意偏移量

for (int i = len-1; i 》= 0; --i) {

//查找 presum 字典,然后将其放到临时数组,注意偏移度

int index = presum[nums[i]-min]-1;

temp[index] = nums[i];

//相应位置减一

presum[nums[i]-min]--;

}

//copy回原数组

System.arraycopy(temp,0,nums,0,len);

return nums;

}

}

好啦,这个排序算法我们已经搞定了,下面我们来扒一扒它。

计数排序时间复杂度分析

我们的总体运算量为 n+n+k+n ,总体运算是 3n + k 所以时间复杂度为 O(N+K);

计数排序空间复杂度分析

我们用到了辅助数组,空间复杂度为 O(n)

计数排序稳定性分析

稳定性在我们最后存入临时数组时有体现,我们当时让其放入临时数组的合适位置,并减一,所以某元素前面的相同元素,在临时数组,仍然在其前面。所以计数排序是稳定的排序算法。

虽然计数排序效率不错但是用到的并不多。

这是因为其当数组元素的范围太大时,并不适合计数排序,不仅浪费时间,效率还会大大降低。

当待排序的元素非整数时,也不适用,大家思考一下这是为什么呢?好啦,今天的文章就到这啦,我们下期再见,拜了个拜

巨人的肩膀

算法导论

极客时间数据结构与算法之美
编辑:lyn

原文标题:计数排序真的不重要?

文章出处:【微信号:TheAlgorithm,微信公众号:算法与数据结构】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
分享:

评论

相关推荐

西门子S5-110A计时、计数模块产品手册

西门子S5-110A计时、计数模块产品手册免费下载。
发表于 05-08 11:40 12次 阅读
西门子S5-110A计时、计数模块产品手册

ET200S高速计数模块使用说明

ET200S高速计数模块使用说明免费下载。
发表于 04-23 09:37 38次 阅读
ET200S高速计数模块使用说明

西门子PLC的计数指令

每次向上计数输入执行从关闭至打开转换时,向上/向下计数器(CTUD)向上计数,每次向下计数输入执行从....
发表于 03-24 09:15 138次 阅读
西门子PLC的计数指令

单光子计数或TCSPC技术说明

1984年,戴斯蒙德·奥康纳(Desmond O’Connor)和戴维·菲利普(David Phil....
发表于 03-16 15:57 108次 阅读
单光子计数或TCSPC技术说明

TBS1000B-EDU系列示波器的性能特点及应用范围

TBS1000B-EDU系列数字存储示波器是专为满足当今大专院校的需求而设计的。它是第一个使用创新的....
发表于 01-25 09:32 163次 阅读
TBS1000B-EDU系列示波器的性能特点及应用范围

排序算法里面的另外一种排序算法:归并排序!

a、这里先定义一个空的数组res,它主要是为了临时存放合并序列排序好的数字;我们从图中可以看到,第一....
的头像 嵌入式ARM 发表于 11-16 16:30 644次 阅读
排序算法里面的另外一种排序算法:归并排序!

程序员的内功:C语言八大排序算法

一 前言 如果说各种编程语言是程序员的招式,那么数据结构和算法就相当于程序员的内功。 想写出精炼、优....
的头像 硬件攻城狮 发表于 10-26 10:33 569次 阅读
程序员的内功:C语言八大排序算法

一堂数据结构和算法的基础课

递归空间 O(logn):递归是一个比较特殊的场景。虽然递归代码中并没有显式的声明变量或集合,但是计....
的头像 算法与数据结构 发表于 09-03 10:28 587次 阅读
一堂数据结构和算法的基础课

Linux操作系统:排序和合并文件内容

在 Linux 上合并和排序文本的方法有很多种,但如何去处理它取决于你试图做什么:你是只想将多个文件....
的头像 如意 发表于 08-25 11:56 987次 阅读
Linux操作系统:排序和合并文件内容

详谈选择排序算法的定义和过程

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数....
的头像 如意 发表于 06-30 17:06 691次 阅读
详谈选择排序算法的定义和过程

实用的排序算法 - 交换排序

实用的排序算法 - 交换排序
的头像 黄工的嵌入式技术圈 发表于 03-20 09:53 665次 阅读
实用的排序算法 -  交换排序

关于STM32的计数与延时

关于STM32的计数和延时
的头像 黄工的嵌入式技术圈 发表于 03-12 11:20 1166次 阅读
关于STM32的计数与延时

Python最简单实现快速排序的办法

快速排序有一个缺点就是对于小规模的数据集性能不是很好。可能有人认为可以忽略这个缺点不计,因为大多数排....
的头像 马哥Linux运维 发表于 01-01 15:02 1101次 阅读
Python最简单实现快速排序的办法

插入排序和冒泡排序哪个更牛逼?

对于时间复杂度的分析,要把最好时间复杂度、最坏时间复杂度、平均时间复杂度分析出来,分别对应了排序算法....
的头像 算法与数据结构 发表于 11-27 16:13 4446次 阅读
插入排序和冒泡排序哪个更牛逼?

怎样将在获取到当前计数后将计数值清零?

TIM_VALUE = TimerValueGet(TIMER0_BASE, TIMER_A); 在获取到当前计数后,怎样将计数值清零 ...
发表于 09-09 07:58 921次 阅读
怎样将在获取到当前计数后将计数值清零?

PWM实验下载不进去是怎么回事?

PWM实验按照手册把RXD和TXD的跳线帽拔了一个插到PA7和PA8起来后上电,再下载就下不进去,开始连接后面一直计数。先...
发表于 09-06 02:34 331次 阅读
PWM实验下载不进去是怎么回事?

如何在OMAPL138上测试代码运行周期?

OMAPL138有两个性能计数寄存器EMUCNT0(0x01C111F0),EMUCNT1(0x01C111F4),运行在CPU/4的时钟频率,在上电...
发表于 08-22 10:56 178次 阅读
如何在OMAPL138上测试代码运行周期?

和你一起一步步看懂排序算法的运行过程

由于右边的 2 已经是排好序的数字,就不再参与比较,所以本轮冒泡结束,本轮冒泡最终冒到顶部的数字 5....
的头像 AI科技大本营 发表于 07-18 14:55 1863次 阅读
和你一起一步步看懂排序算法的运行过程

PLC常用数制及转换方法

数制也称计数制,是指用一组固定的符号和统一的规则来表示数值的方法。按进位的原则进行计数的方法,称为进....
的头像 工控资料窝 发表于 05-06 16:48 1805次 阅读
PLC常用数制及转换方法

二维数组升序、降序排列

二维数组升序降序排列 同时可区分相等的数据 ...
发表于 04-19 14:56 1465次 阅读
二维数组升序、降序排列

冒泡排序算法原理

然后对剩下的未排序好的项目再进行扫描,使它们的最大者换到表的最后。以此类推,直到将表全部排序好为止。....
的头像 电子发烧友网工程师 发表于 03-29 16:57 4801次 阅读
冒泡排序算法原理

数据库读取数据进行冒泡法排序子程序

数据库读取数据进行冒泡法排序子程序
发表于 03-22 11:12 1084次 阅读
数据库读取数据进行冒泡法排序子程序

十大经典排序算法动画与解析

从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中....
的头像 电子发烧友网工程师 发表于 02-25 09:20 5255次 阅读
十大经典排序算法动画与解析

选择排序算法C语言的实现

选择排序算法C语言的实现.选择法排序原理:一次选定数组中的每一个数,记下当前位置并假设它是从当前位置....
的头像 电子设计 发表于 02-20 09:19 1105次 阅读
选择排序算法C语言的实现

电子售票员实验电路

目前无人售票车逐步增加,及时统计上车人数,刷卡人数、投币买票人数,电子售票员是很需要的。
的头像 电子设计 发表于 02-09 09:01 728次 阅读
电子售票员实验电路

这10个Excel小秘技你知道吗简单教学

话说你天天加班,大概是因为Excel用得不好…送你10个不简单的Excel小技巧,祝你颈椎病早日康复
的头像 网优雇佣军 发表于 12-23 15:06 2315次 阅读
这10个Excel小秘技你知道吗简单教学

C语言中的排序算法了解

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列....
的头像 电子发烧友网工程师 发表于 11-12 14:52 1483次 阅读
C语言中的排序算法了解

几种c语言程序的排序包括应用程序等资料免费下载

本文档的主要内容详细介绍的是几种c语言程序的排序包括应用程序好资料免费下载包括了:堆排序,改进冒泡排....
发表于 09-29 08:00 335次 阅读
几种c语言程序的排序包括应用程序等资料免费下载

简单选择排序算法的流程,代码,性能等详细资料概述

简单选择排序是一种选择排序。 选择排序:每趟从待排序的记录中选出关键字最小的记录,顺序放在已排序的....
的头像 算法与数据结构 发表于 08-18 10:47 3035次 阅读
简单选择排序算法的流程,代码,性能等详细资料概述

网络搜索-填补信息断层的详细中文资料免费下载

本文档的主要内容详细介绍的是网络搜索-填补信息断层的详细中文资料免费下载
发表于 08-17 18:01 446次 阅读
网络搜索-填补信息断层的详细中文资料免费下载

请问有没有1GHz或以上的计数方案?

有没有1GHz以上的计数解决方案
发表于 07-24 07:32 427次 阅读
请问有没有1GHz或以上的计数方案?

常用排序算法分析

一种是比较排序,时间复杂度O(nlogn) ~ O(n^2),主要有:冒泡排序,选择排序,插入排序,....
的头像 算法与数据结构 发表于 07-13 16:13 1029次 阅读
常用排序算法分析

排序模拟:ADS中文基础教程(14)

ADS中文基础教程
的头像 EE techvideo 发表于 07-05 00:37 2274次 观看
排序模拟:ADS中文基础教程(14)

常用的非比较排序算法:计数排序,基数排序,桶排序的详细资料概述

这篇文章中我们来探讨一下常用的非比较排序算法:计数排序,基数排序,桶排序。在一定条件下,它们的时间复....
的头像 Linux爱好者 发表于 06-18 15:11 5432次 阅读
常用的非比较排序算法:计数排序,基数排序,桶排序的详细资料概述

常用的排序算法总览

我们通常所说的排序算法往往指的是内部排序算法,即数据记录在内存中进行排序。
的头像 C语言编程学习 发表于 06-13 18:18 1386次 阅读
常用的排序算法总览

如何将二维数组中相同的一维数组合并并计数?所有身家悬赏急求谢谢大佬

怎么将图中相同的行,找出来合并,并且找出其数量,将合并后的数组及其数量组成新的二维数组输出呀?谢谢大家了。新手没有几个积...
发表于 05-27 09:38 1135次 阅读
如何将二维数组中相同的一维数组合并并计数?所有身家悬赏急求谢谢大佬

探讨一下常用的比较排序算法知识

选择排序也是一种简单直观的排序算法。它的工作原理很容易理解:初始时在序列中找到最小(大)元素,放到序....
的头像 人工智能爱好者社区 发表于 05-23 11:25 2662次 阅读
探讨一下常用的比较排序算法知识

EA定时器双向计数工作原理

什么是EV定时器?原理是什么?有例子吗?
发表于 03-26 21:32 1327次 阅读
EA定时器双向计数工作原理

labview数组的选择性排序如何做?

我会冒泡排序,但是我做选择性排序时,不知道如何将最外层for循环的每层最大值给传递下去, 交换索引地址也出现了问题 ...
发表于 03-24 14:13 1978次 阅读
labview数组的选择性排序如何做?

MM32 如何使用定时器做脉冲计数

来源 灵动MM32一、应用简介在实际应用的一些产品上可能需要到对脉冲的个数进行计数,本章我们来讲一下如何使用TIM来做一个脉...
发表于 03-22 17:53 1835次 阅读
MM32 如何使用定时器做脉冲计数

一种检索结果相关排序算法

针对数学表达式符号种类繁多、结构复杂多变、语法语义丰富等特点,提出一种检索结果相关排序算法,利用犹豫....
发表于 02-23 10:38 290次 阅读
一种检索结果相关排序算法

数据结构常见的八大排序算法

本文总结了数据结构常见的八大排序算法。详细分析请看下文
发表于 02-05 15:26 961次 阅读
数据结构常见的八大排序算法

计数报警器电路设计方案汇总(多款模拟电路设计原理图详解)

本文主要介绍了计数报警器电路设计方案汇总(多款模拟电路设计原理图详解),方案二主要由直流电源电路(整....
的头像 报警电路图|报警器电路图 发表于 01-29 10:30 13873次 阅读
计数报警器电路设计方案汇总(多款模拟电路设计原理图详解)

一文了解冒泡排序

冒泡排序是一种交换排序。 什么是交换排序呢? 交换排序:两两比较待排序的关键字,并交换不....
的头像 算法与数据结构 发表于 01-17 12:47 2010次 阅读
一文了解冒泡排序

基于排序学习的推荐算法

排序学习技术尝试用机器学习的方法解决排序问题,已被深入研究并广泛应用于不同的领域,如信息检索、文本挖....
发表于 01-16 15:50 518次 阅读
基于排序学习的推荐算法

排序算法及其在OFDM中的应用

随着科技的飞速发展,排序算法不再仅限于计算机领域,越来越来多优异的排序算法开始应用于无线通信领域。O....
发表于 12-27 17:03 293次 阅读
排序算法及其在OFDM中的应用

基于标签优先的抽取排序方法

针对微博关键词抽取准确率不高的问题,提出一种基于标签优先的抽取排序方法。该方法利用微博本身具有的社交....
发表于 12-25 15:04 394次 阅读
基于标签优先的抽取排序方法

个体排序策略的改进型NSGA-Ⅱ算法

针对经典快速非支配排序遗传算法(NSGA-Ⅱ)中基于拥挤距离的种群多样性保持策略不能客观反映个体间真....
发表于 12-19 17:00 316次 阅读
个体排序策略的改进型NSGA-Ⅱ算法

基于距离度量的多样性图排序方法

有效结合查询相关性和多样性的扩展相关性是多样性图排序问题的一种优化目标.基于扩展相关性的多样性图排序....
发表于 12-19 11:37 390次 阅读
基于距离度量的多样性图排序方法

踪迹聚类下组织实体的重要度排序方法

针对简单套用交接网络等社会网络分析方式不能很好地反映踪迹聚类生成的一系列流程的组织实体的重要度的问题....
发表于 12-19 11:20 248次 阅读
踪迹聚类下组织实体的重要度排序方法

基于字符串排序的高效保密数据库查询

安全多方计算是近年来国际密码学界研究的热点问题之一,是信息社会隐私保护的核心技术.保密地将字符串按照....
发表于 12-15 11:42 337次 阅读
基于字符串排序的高效保密数据库查询

基于检索结果排序的伪相关反馈

随着Web的普及,越来越多的用户希望从互联网上获取信息。对于目前主流的基于关键词的搜索方式,用户必须....
发表于 12-13 14:39 270次 阅读
基于检索结果排序的伪相关反馈

基于GPU的视频流人群实时计数

为了解决人群遮挡严重、光照突变等恶劣环境下人群计数准确率低的问题,提出基于混合高斯模型(GMM)和尺....
发表于 12-07 15:38 434次 阅读
基于GPU的视频流人群实时计数

准序化供货模式下的混装线重排序

准序化供货是在准时制的基础上对零部件进行排序供货,其顺利实施需要依靠稳定的生产序列与零部件交付的可靠....
发表于 12-05 15:16 213次 阅读
准序化供货模式下的混装线重排序

经典排序算法和JS实现案例分析

经典排序算法冒泡排序原理: 1.比较相邻的元素,如果第一个比第二个大,就交换位置。 2.重复以上步骤....
发表于 11-27 17:40 824次 阅读
经典排序算法和JS实现案例分析

S7-1200计数测量功能及结构

S7-1200 产品从固件版本V4.1 起新增了高速计数器的周期测量功能,该功能通过CTRL_HSC....
发表于 09-27 11:33 773次 阅读
S7-1200计数测量功能及结构

S7-1500、ET系列的计数、测量、位置检测

本文档将帮助您对模块进行组态和编程,以完成 S7-1500, ET 200MP 和 ET 200SP....
发表于 09-27 10:34 518次 阅读
S7-1500、ET系列的计数、测量、位置检测

基于R7F0C809的外部事件计数与数据存储的设计应用

本文档介绍了基于R7F0C809的外部事件计数与数据存储的设计应用。
发表于 09-12 20:00 424次 阅读
基于R7F0C809的外部事件计数与数据存储的设计应用

排序问题的动画演示报告

本篇文档介绍了一款常见排序算法(冒泡排序,归并排序,快速排序)动态演示软件的设计与实现。首先,在文....
发表于 07-14 16:20 456次 阅读
排序问题的动画演示报告