MIT算法导论五 线性时间排序

-分析基于比较的排序能够达到的最快效率
-介绍几种非比较的线性时间排序算法

排序最快能够达到多快的速度?
取决于你使用的计算模型里,哪些操作是被允许的
插入排序、归并排序、快速排序、堆排序,都是基于比较的排序算法,即只能做比较操作来决定元素的相对顺序
最坏情况下的时间复杂度最快的是Θ(nlgn)

我们能够做的比Θ(nlgn)更快么?
决策树模型
以三个元素的比较举例,树上的每个节点表示一次比较操作,根据比较结果选择不同的路径

MIT算法导论五 线性时间排序_第1张图片
决策树

通常情况,有n个元素需要排序
每个非叶子节点(内节点)有一个下标i:j,分别在1和n之间,表示需要比较ai和aj的大小,每个内节点有两个子树,左边的子树表明ai<=aj时,算法需要做什么,右边子树同理
每个叶子节点代表一种排序
决策树的复杂程度是n的指数级,不适合用于表达排序算法,但是任何一种比较排序算法都有其相应的决策树

树的深度:任意一条路径,代表算法执行路径,最坏情况运行时间,即树的最大深度为Ω(nlgn)

定理:决策树排序的下界,决策树针对任意n个元素排序,它的高度至少是nlgn
证明:
# 决策树中叶节点最少是n!(输入值的所以排列)
如果树的高度是h,叶子的数量为2^h(二叉树),可以得出
n!<= 2^h               | 不等式两边取对数
=> h >= lg(n!)          |  lg函数单调递增
=> h >= lg(n/e)^n       | 斯特林公式,取n!的近似值
=> h > nlgn - nlge = Ω(nlgn)

归并排序和堆排序算法是渐进最优的。随机化快速排序算法在理想情况下也是渐进最优的

线性时间排序

尽量在线性时间内完成排序。在不用并行算法,无论你做什么,你必须遍历,因为你得去遍历这些数据,否则你无法对其正确排序,所以线性时间是能期望的最好结果

计数排序

输入:一组数组A[1...n],设定数组元素的取值范围A[j]∈{1,2,3...k}
输出:排序数组B[1...n]
辅助存储序列:C[1...n]

for i <- 1 to k
    do C[i] <- 0
for j <- 1 to n
    do C[A[j]] <- C[A[j]] + 1
for  i <- 2 to k
    do C[i] <- C[i] + C[i-1]
for j <- n downto 1
    do B[C[A[j]]] <- A[j]
      C[A[j] <- C[A[j] -1

下面通过一个例子,分别看看这四个for循环做的事情。
第1个for循环初始化将C置0。
第2个for循环遍历输入序列A,计算A中等于C对应位置的个数来填充辅助数组C
第3个for循环计算C中当前位置之前所有数字之和并填充C
第4个for循环,从后往前遍历A中数据,根据C中计算结果,将A中数据放在B中正确的位置。例如A中第一个元素4,则C[4]即为元素4在B中所处的正确位置,即4,也就是目前B中空缺的位置


MIT算法导论五 线性时间排序_第2张图片
1-3

MIT算法导论五 线性时间排序_第3张图片
4

计算排序算法的算法效率由伪代码可以容易知道,复杂度为Θ(n + k),如果k比nlgn大我们就用归并排序,如果它比nlgn小就用计数排序

如果你在处理的数字长度为1字节,k仅为2^8,这就是256,你需要的辅助数列长度为256,这很快O(256 + n),无论n多大这都是n的线性时间。但是如果数字更大达到32位。因为这时需要的辅助空间就是2^32,16G。

计数排序是一种 稳定排序:对于相等的元素,它保持了他们在输入数列中的顺序


基数排序

利用计数排序作为小数据规模的子程序,结合这个算法那去处理更大规模的数字
基数排序首先对最后一位进行排序,然后在对高位进行排序,需要用到一种稳定排序算法

MIT算法导论五 线性时间排序_第4张图片
基数排序
算法的正确性
归纳假设,对t位置进行排序,前提在第t - 1位已经排好序。在t位上,有两种情况,
对于两个数字不相等的t,基于稳定性原则,可知它们保持原顺序。
对于两个数字不相等的t,t能够正确决定他们的顺序。

基数排序的算法复杂度
将计数排序作为辅助的稳定排序算法(目前了解的低于nlgn复杂度的算法)
对每一位数字的排序用计数排序,但是不想按照每一个数字位来进行依次排序,那样将会失去太多灵活性。因为数可以用任意形式来表示,比如用二进制表示的数,假设有n个整数,二进制整数设为b bit长度,n个整数取值范围在0到2b-1之间,把连续的bit看作一位
把每个整数拆分为b / r位数字,每个数字都是r位长,b/r是算法需要运行的轮数,2r则是每位数字可以取的最大值(计数排序中的k)
计数排序的运行时间是T(n) = Θ(b/r ·(n+2r))
通过选择r来减少T(n)

需要用到一些数学知识,问题转换为求一元函数的最小值
对这个函数关于r求导,求导数为0时的解
r越大那么b/r也就是算法的轮数越少,但是根据后面2^r这一项可知r不可能太大
当r >> lgn时将会指数级的增长
我们想要的是让n而非2^r来决定整个多项式的大小,假设选择r为这种情况下的最大值,即r = lgn,可以得到运行时间的上界
T(n) = O(b/lgn ·(n))

你可能感兴趣的:(MIT算法导论五 线性时间排序)