计数排序是排序算法的一种,冒泡、插入、选择、快排等都是非常经典、妙不可言的排序算法,下面来记录一笔关于计数排序的故事。
因为对于我个人理解来说,算法是一门比较烧脑的学科,所以我总是想借用某些实际的场景来说明问题,这样不但自己记的牢,也能
给读者一种轻松的心情。不知道大家是否印象中还有这么一段音响:
这次我们班月考的总成绩排名如下:“雷军、张亚勤并列第1名,张朝阳、李彦宏、马化腾并列第3名,任正非第6名......,马云倒数第一....”,好了,风趣归风趣,言归正传,这里我们抽象出一个这样的模型来:
当A、B并列第一名的时候,需要占据2个名次,所以接下来只能从第(1+2)名开始,而当C、D、E并列第3名的时候,又要占据3个坑,所以接下来又只能从第(3+3)名开始,可以发现,每个人的名次其实和两个因素相关,那就是:
1.上一个人的名次
2.上一个名次的人数
一旦知道以上两个元素,每个人的名次也就确定了,那么它在班级里相应的成绩位置也就确定了;
这里的计数排序的原理其实就如同上面的排名一样,“计数”可以理解为是“计算个数”,那么计算什么个数呢,当然是计算相同成绩的人的个数啦,那么我们就对以下的这张成绩单来排个序吧:
「任正非:85分 雷军:99分 张朝阳:90分 马云:72分 李彦宏:90分 张亚勤:99分 马化腾:90分」
首先,以我们最熟悉的方式来把上面的分数抽象到我们的数组中:
[85,99,90,72,90,99,90]
下面我们先来看看把成绩相同的给抽取出来,只需要以O(n)的时间复杂度遍历一边即可,
我们发现得90分的有3个人,得99分的有2个人,得85分的有1个人,而得72分的也有1个人,这时候我们先把抽取出来的数据保存下来,
这里可以巧妙一点,我们再建一个数组array,用分数作为数组的下标,而取得相应分数的人的个数作为数组的值,就成为以下的形式:
[....................................... 1 ..............1 .........3..............2..............................................]
下标:0 1 2 3 4 5...................72 ...........85........90............99.............................................
好了,我们的第二轮数据也已经出来了,这时候你发现,其实我们新建的这个数组array中大部分都是空的,只用到了极少数的空间,
其实到这里你已经可以发现,各个人的位置也已经确定下来了,72分的有一位,显然排在第1个位置,而85分的也有1位,那就排在第
(1+1=2)的位置,而90分的人有3个,所以需要3个位置,所以要排到(1+1+3=5)的位置,99的有两位,所以要排到(1+1+3+2=7)的位置
所以依次如下放置就行:
【1 2】 【3,4,5】 【6,7】
72 85 95 99
好了,基本的思路已经出来,具体的算法以及写法每个人都各异,最关键的还是在于“计数”这个思想,以成绩排名这个例子来做场景,也只是为了能够让人更加快得感受到这种算法的妙处。
PS:如果阁下有比较好的理解与建议,还请留下一言半句,多谢多谢!