数据结构与算法系列11--桶排序、计数排序、基数排序

线性排序算法介绍

1.线性排序算法包括桶排序、计数排序、基数排序
2.线性排序的算法的时间复杂度为:O(n)
3.此三种排序算法都不涉及元素之间的比较操作,是非基于比较的排序算法。
4.对要排序的数据要求很苛刻,只能适用在某些特殊场景,所以重点掌握此3钟算法的适用场景。

桶排序

算法原理:
将要排序的数据分到几个有序的桶里,每个桶里再单独进行快速排序。桶内排完序后,再把桶内的数据按照顺序依次取出组成一个新的序列,这个新的序列就是有序的了。
使用条件:
1.要排序的数据可以很容易的就能划分到m个桶里,并且桶与桶之间有着天然的大小顺序。
2.数据在各个桶之间的分布是比较均匀的。因为如果有些桶里的数据非常多,有些非常少,很不平均,那桶内数据排序的时间复杂度就不是常量级了。在极端情况下,如果数据都被划分到一个桶里,那就退化为O(nlogn)的排序算法了。
适用场景:
桶排序比较适合在外部排序中,这里的外部排序是指数据储存在外部磁盘中,数据量比较大,内存有限,无法将数据一次性全部加载到内存中。
应用案例:
需求描述:
有10GB的订单数据,需按订单金额(假设金额都是正整数)进行排序,但内存有限,仅几百MB
解决思路:
首先,我们先扫描一遍文件,查看订单金额所处的数据范围。假设我们扫描后得到订单的数据范围是1元到10万元,那么我们将所有的订单数据划分到100个桶里,第一个桶我们储存1-1000元之间的数据,第二桶我们储存1001-2000之间的数据,依次类推,每一个桶对应一个文件,并按照金额范围的大小顺序命名(00,01,02…99)。然后将100个文件依次放到内存中用快排进行排序。所有文件排好序后,只需要按照文件命名序号从小到大依次读取每个小文件,并写到大文件中即可。
注意: 如果分成的单个小文件还是大于内存使用大小,无法加载到内存中,则针对此文件继续按照前面的思路进行划分处理即可。

桶排序的时间复杂度为什么是O(n)呢?
如果要排序的数据有n个,我们把它们均匀地划分到m个桶内,每个桶里就有k=n/m个元素。每个桶内部使用快速排序,时间复杂度为O(klogk)。m个桶排序的时间复杂度就是O(mklogk),因为k=n/m,所以整个桶排序的时间复杂度就是O(nlog(n/m))。当桶的个数m接近数据个数n时,log(n/m)就是一个非常小的常量,这个时候桶排序的时间复杂度接近O(n)。

计算排序

算法原理:
1.计数其实就是桶排序的一种特殊情况。
2.当要排序的n个数据所处范围并不大时,比如最大值为k,则分成k个桶
3.每个桶内的数据值都是相同的,就省掉了桶内排序的时间。
使用条件:
1.只能用在数据范围不大的场景中,若数据范围k比要排序的数据n大很多,就不适合用计数排序;
2.计数排序只能给非负整数排序,其他类型需要在不改变相对大小情况下,转换为非负整数;
3.比如如果考试成绩精确到小数后一位,就需要将所有分数乘以10,转换为整数。
应用案例:
如果你所在的省有50万考生,如何通过成绩快速排序得出名次呢?
考生的满分是900分,最小是0分,这个数据的范围很小,所以我们可以分成901个桶,对应分数从0分到900分。根据考生的成绩,我们将这50万考生划分到这901个桶里。桶内的数据都是分数相同的考生,所以并不需要再进行排序。我们只需要依次扫描每个桶,将桶内的考生依次输出到一个数组中,就实现了50万考生的排序。因为只涉及扫描遍历操作,所以时间复杂度是O(n)。

基数排序

算法原理:(这里以排序10万个手机号为例子来说明)
1.比较两个手机号码a,b 的大小,如果在前面几位中a已经比b大了,那后面几位就不用看了。
2.借助稳定排序算法的思想,可以先按照最后一位来排序手机号码,然后再按照倒数第二位来重新排序,以此类推,最后按照第一位重新排序。
3.这样经过11次排序之后,手机号码就变为有序了。
4.在按位排序时,因为整个数据范围非常小(即0~9之间的数据),我们可以使用前面的桶排序或者基数排序进行排序,因为他们的时间复杂度是O(n),因为这里需要11次排序,所以总的时间复杂度是O(11*n),忽略常数值,所以最终的时间复杂度是O(n)。
使用条件:
1.要求数据可以分割成独立的位来比较。
2.位之间有递进关系,如果a数据的高位比b数据大,那么低位就不用比较。
3.每一位的数据范围不要太大,要可以用线性排序进行排序,否则基数排序的时间复杂度就无法做到O(n)。

猜你喜欢

转载自blog.csdn.net/qq_34493908/article/details/83546373