算法导论--线性时间排序

Counting sort

counting sort假设待排序的数组元素是整型,并且都在一个范围内,例如学生们的考试分数(没有0.5分)在0-100之间,这样我们可以用O(n)的时间来排序。
假如我们要给A[1…n]排序,我还需要两个数组,B[1…n]来排过序的结果,数组C[0…k]来存储临时变量。伪代码如下:

这里写图片描述

来解释一下伪代码:
2-3行:初始化C数组
4-5行:从头开始扫描输入数组,也就是A数组,给A中的元素计数。比如在A数组中每遇见一次5,那么C[5] = C[5]+1
7-8行:C[i]就是A数组中小于等于i的数字的数量
10-12行: 这个不太好讲,有点绕,自己跑个例子就懂了
时间复杂度是多少呢,2-3行循环k次,4-5行循环n次,7-8行循环k次,10-12也是O(n)的时间复杂度,所以countingSort所花费的是线性时间。

基数排序

基础排序的意思其实就是按位排序,例子如下

这里写图片描述

可以看出,上述过程先根据个位排序,然后是十位,最后是百位,伪代码如下:
这里写图片描述
第二行代码里说要在通过某一位进行排序的时候,必须要用稳定排序。这样做的原因是因为,这不会影响之前“位”的排序结果。因为每一个位的数字是有0-9,所以用counting-sort来为每一位进行排序。
时间复杂度是O(d(n+k))其中d是数字的最大位数,n是待排序数字的数量,k是每一位可能去到数字的个数。例如上例中为三位十进制数排序,d = 3; k = 10

桶排序

桶排序假设输入都是从均匀分布抽样出来的,这样的排序时间复杂度为O(n)。这里假设输入的元素在[0 ,1)之间。
如下图例子:

这里写图片描述

B数组的每一个元素是一个链表的开头,每个链表存储一个特定区间的数组。例如B[1]链表存储区间为[1,2)之间的元素。
伪代码如下:
这里写图片描述
第1-4行:初始化B数组
第5-6行:扫描A数组,将A数组的元素插入到B数组的特定位置
第7-8行:利用插入排序给B数组的每一个链表排序
第9行:将每一个链表按顺序展开。

时间复杂度:可以看出唯有第8行的插入排序有些争议,插入排序不是最坏情况下O(n^2)的复杂度吗,很奇怪是吧,我也很奇怪,但是之前说过,暂时先不做特别复杂的数学分析,这里先略过了。反正捅排序的时间复杂度是O(n)