您的位置:首页 > 其它

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

2015-03-12 19:26 706 查看
第五课主要引出了两个非常有趣的排序算法——它们的时间复杂度竟然是θ(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)这个算法也是线性尺度的排序算法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: