线性排序方法

一、基本概念

排序算法的时间复杂度是线性的,我们把这类排序算法叫做线性排序,例如桶排序计数排序基数排序这三种排序算法的时间复杂度是线性的,都是O(n)。之所以能做到线性的时间复杂度,主要原因是这三个算法是非基于比较的排序算法,不涉及元素直接的比较操作;

二、桶排序:

核心思想是将要排列的数据分到几个有序的桶里,每个桶里的数据再单独进行排序。桶内排序完之后,再把每个桶里的数据安装顺序依次取出,组成的序列就是有序的了。如下图所示:

线性排序方法_第1张图片

 

时间复杂度分析:如果要排序的数据有n个,我们把他们均匀的划分到m个桶内,每个桶里的元素就是k=n/m,对每个桶里的元素使用快速排序时间复杂度是O(klogk),m个桶的时间复杂度就是O(m*klogk),k=n/m,所以时间复杂度是O(nlog(n/m)),当桶的个数m接近n时,log(n/m)就是一个很小的常量,这个时候桶排序的时间复杂度接近O(n)。

使用场景

桶排序对排序数据的要求是非常苛刻的。首先,要排序的数据需要很同意划分成m个桶,并且桶与桶之间有着天然的大小顺序。这样每个桶内的数据排序完之后,桶与桶之间的数据不需要再排序。其次,数据在各个桶之间的分布是比较均匀的,如果经过桶的划分之后,有些桶里的数据非常多,有些桶里的数据非常少,很不均匀,那桶内数据排序的时间复杂度就不是常量级的了,在极端情况下,如果所有的数据都被分到了一个桶里,时间复杂度就退化为O(nlogn)。

桶排序比较适合用在外部排序中。所谓的外部排序就是数据存储在外部磁盘中,数据量比较大,内存有限,无法将数据全部加载到内存中。

比如说我们有 10GB 的订单数据,我们希望按订单金额(假设金额都是正整数)进行排序,但是我们的内存有限,只有几百 MB,没办法一次性把 10GB 的数据都加载到内存中。这个时候该怎么办呢?

  (1) 先扫描一遍文件,看订单金额所处的数据范围。们将所有订单根据金额划分到k个桶里,每个桶里大概存储100mb的订单数据,

  (2) 将这100个小文件一次放在内存中,用快排进行排序,并将其写到一个文件中;

  (3) 如果分割之后,某个区间的数据量非常大,这种情况下,可以对此区间内的数据继续进行分割;知道所有的文件都能读入内存为止。

三、计数排序(Counting Sort)

计数排序其实是桶排序的一种特殊情况。当要排序的n个数据,所处范围不大,最大值为k,我们就可以把数据划分成k个桶。每个桶内的数据值都是相同的,省掉了桶内排序的时间。例如:高考查分系统,考生的满分是 900 分,最小是 0 分,这个数据的范围很小,所以我们可以分成 901 个桶,对应分数从 0 分到 900 分。根据考生的成绩,我们将这 50 万考生划分到这 901 个桶里。桶内的数据都是分数相同的考生,所以并不需要再进行排序。我们只需要依次扫描每个桶,将桶内的考生依次输出到一个数组中,就实现了 50 万考生的排序。因为只涉及扫描遍历操作,所以时间复杂度是 O(n)。

计数排序为什么叫做计数排序,需要分析计数排序算法的实现过程

示例:一组数据进行计数排序,数值范围在0-5之间,2,5,3,0,2,3,0,3,使用数组c[6]表示桶,下标表示数值大小,值表示数值个数,结果为[2, 0, 2, 3, 0, 1],如何快速计算出每个数值在排序后的数组中处于什么位置,这里采用的是累计计数,处理后的结果为[2,2,4,7,7,8];此时我们开始从后往前依次遍历原有数组,第一个为3,我们看到c数组中下标为3的值为7,表示在此3在排序后的数组中下标为6,此时将c数组中下标为3的数组进行-1(减去1)操作;第二个遍历到的元素为0,查到c数组中的数值为2,那么在排序后的数组中下标为1,c[0]继续进行-1操作,依次类推。利用了另外一个数组来计数的实现方式,这也是这种排序算法为什么叫计数排序,计数排序只能用在数据范围不大的场景中,如果数据范围k比要排序的数据n大很多,就不适合用计数排序了。而且计数排序只能给非负整数排序,如果要排序的数据是其他类型的,要将其在不改变相对大些的情况下,转化为非负整数。

四、基数排序

示例

线性排序方法_第2张图片

 

基数排序对要排序的数据是有要求的,需要可以分割出独立的“位”来比较,而且位之间有递进的关系,如果 a 数据的高位比 b 数据大,那剩下的低位就不用比较了。除此之外,每一位的数据范围不能太大,要可以用线性排序算法来排序,否则,基数排序的时间复杂度就无法做到 O(n) 了。

你可能感兴趣的:(数据结构与算法,线性排序,数据结构,排序算法,桶排序,基数排序)