【算法导论】第五课 线性排序(基数排序 计数排序)

来源:互联网 发布:手机数据网络自动开启 编辑:程序博客网 时间:2024/05/16 23:33

第五课主要引出了两个非常有趣的排序算法——它们的时间复杂度竟然是θ(n),也就是说时间复杂度是线性的。

首先来看看之前提到过的几个排序算法:
quicksort ——θ(nlgn)
heapsort——θ(nlgn)
merge sort——θ(nlgn)
insert sort——n^2
所有这些排序算法,能否比nlgn更快? 
不能,因为他们都采用了同样的一个模型,比较算法模型。也就是在排序的时候都会取两个数进行比较,这样的算法的局限性导致不可能超过nlgn的时间复杂度,我们可以用决策树的模型来证明:
例:决策树 a1 a2 a3
大于 1比2 小于
2比3 1比3
123 1比3 213 2比3
132 312 231 321
通过每一次的对比,决策树分出了两个分支,现在要对n个元素进行排序,ai,aj i,j在1~n的范围内
构造这样一个决策树,左边 ai≤aj,右边是ai>aj,每一个叶子节点都是一种排序的可能结果,一共有n!个结果
这个决策树的高度,也就是最长的路径,树的深度就是需要求的时间尺度。
证明:一共是有n!个叶子节点,假设这个树的高度是h,那么高度是h的数二分节点最多是2^h
n!≤2^h
lgn!≤h
利用斯特林公式,n!近似等于(n/e)^n
h≥nlg(n/e)=nlgn-nlge
所以h=Ω(nlgn)
得证!

还有一些排序算法不能用简单的决策树来表示,突破决策树方法的关键是我们意识到,我们其实在使用比较排序模型的时候假设了对于一个n数列来说,只有一棵树。这才导致了这个模型是有极限的。下面来介绍两个排序算法
1.计数排序
写出计数排序的伪代码:
A={1,2,.....k} A是待排序数列,A里的值取值范围在1~k的整数
B[i] 是A排序的结果数列
C[i] 是辅助序列 C的长度是k,用来记录A中各个整数出现的次数

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
结果
从伪代码来看,是不是晕了???
例子:排序A= 4,1,3,4,3
C=0000然后变成1022记录了每一个数字出现的次数,然后将C的每项都递归的加起来,得到C=1135
然后来得出结果
j=5时 B[3]=A[5]=3 然后 C[3]减1
j=4时 B[5]=A[4]=4 然后 C[4]减1
……
这样就通过辅助数列把A排列成了B
我们来计算一下这个算法的复杂度
T(n)=θ(n+k)
一个线性时间复杂度的算法就产生了。最终的时间其实还和k相关,k如果较大的话还不如快速排序

我们这里提到的算法都是稳定排序算法:稳定排序算法是指保证了相等元素的相对位置稳定不变

再来看第二个算法
2.基数排序算法
在排序的时候对末位开始排序,然后再对第二位开始排序
例子:
对329 457 657 839 436 720 355进行排序
先排末位得到:720 355 436 457 657 329 839
再排第二位得到:720 355 436 457 657 329 839
最后再排首位得到结果
那么在每一轮的排序中,我们都可以使用计数排序算法。

在计算机假设有n个整数在0~2^b-1范围内,也就是说每个数的的b位二进制数,我们对他们进行排序
可以把整数拆分成b/r个段,每个段长度都有r
b/r是一共要比较的轮数,k=2^r
T(n)=b/r * (n+k)=b/r * (n+2^r)
那么我们可以选取恰当的r来得到最好的T(n),r=lgn的时候得到最好的结果
T(n)=O(b*n/lgn)
若b=n^d
那么T(n)=θ(dn)这个算法也是线性尺度的排序算法。

0 0