算法导论习题6-堆排序

来源:互联网 发布:wps数据有效性设置两个 编辑:程序博客网 时间:2024/05/21 09:54

思考题6-1 用插入方法建堆,最坏情况下,需要花费Theta (nlgn)时间。

1、问题说明:
在读书中介绍堆的算法前,我一直都以为建堆是采用本题所介绍的插入式方法来完成的。对这种插入式建堆的直觉性算法分析,n个元素依次插入堆中,每个元素花费的时间是O(<mce:script type=lgn)" class="ee_img tr_noresize" eeimg="1" style="vertical-align: middle;">,那么n个元素总的运行时间上界为O(nlgn)。在读书中介绍的建堆的算法时,我很奇怪为什么采用自底向上建立子堆的方式(中文版p76 6.3节介绍的BUILD-MAX-HEAP算法)。而且凭借直觉性,这种方法的运行时间上界可能是O(nlgn)。在读了书中算法数学分析后,我才发现这种直觉性分析是多么不可靠,BUILD-MAX-HEAP建堆的算法时间有个更好的上界是O(n),具体分析如下:
n个元素的二叉堆的高度H为left[ O(lgn)right] ,高度(Height)为h的节点数最大为left[frac{n}{2^{h+1} } right] +1。高度为h的节点创建子堆得时间为O(h)。BUILD-MAX-HEAP的代价为:

sum_{h=0}^{[lgn]}{([frac{n}{2^{h+1} } ]+1) O(h)}  = O(n sum_{h=0}^{[logn]}{frac{h}{2^{h}}) =  O(n sum_{h=0}^{infty}{frac{h}{2^{h}}) = O(n frac{x}{{1+x}^2})|_{x=frac{1}{2}} = O(n)

现在来分析题中BUILD-MAX-HEAP'的代价。
n个元素的二叉堆的深度度D为left[ O(lgn)right] ,深度度(Depth)为d的节点数最大为2^d。最坏情况下,插入一个新的节点到高度为h的堆得时间Theta (d)
1)用上面提到的直觉性方法,可以知道这个算法有一个上界为O(nlgn)
2)BUILD-MAX-HEAP的代价可以表示为:

T = sum_{d=0}^{[lgn]}{{2^dTheta (d)}  geq sum_{d=0}^{[lgn]-1}{{2^dd}
sum_{d=0}^{n-1}{{2^dd}  = T',

T ' +  2^n n = sum_{d=0}^{n-1}{{2^dd}  + 2^n n = 0 + sum_{d=1}^{n}{{2^dd}  = sum_{i+1=1}^{n}{{2^{i+1}{(i+1)}} = 2sum_{i=0}^{n-1}{{2^{i}{i}} + 2sum_{i=0}^{n-1}{{2^{i}}

T ' +  2^n n = 2T' + 2^{n+1} Rightarrow  T' = (n-2)2^n

Rightarrow  Tgeq (n-2)2^n |_{0}^{[lgn]-1}  = Omega (nlgn)

综合1,2. BUILD-MAX-HEAP'的最坏情况下的代价为 Theta (nlgn)

2、总结:算法导论 《instructor's Manual》中有另外一种方法来证明。
BUILD-MAX-HEAP'的最坏情况下的代价可以表示为
sum_{i=1}^{n}{Theta [lgi]} geq sum_{i=[frac{n}{2}]+1}^{n}Theta([lg([frac{n}{2}])+1]) geq sum_{i=[frac{n}{2}]+1}^{n}Theta([lg(frac{n}{2})]) geq frac{n}{2}Theta(lgn)
可以看到,后n/2个元素的插入的最坏情况下的时间代价就已经是Theta (nlgn)了。
这样就很容易明白了建堆算法为什么不采用插入方式建堆了。
算法分析就是求上下界的问题,对BUILD-MAX-HEAP建堆方法进行直觉性方法分析可以得到一个上界,可以说直觉性分析方法是正确的,通过数学运算分析可以得到一个更小的上界,这种方法也是正确的,但是结果比直觉性方法好,但是过程更复杂。《计算机程序设计艺术》的算法分析比《算法导论》的算法分析更加精确,但是用的数学方法更加晦涩难懂。因为基础有限,我不能以开始就陷入过于复杂的数学分析中,所以,这一个时期,我应该侧重阅读《算法导论》,并且认真做好每个习题,《计算机程序设计艺术》应该先放一放,只需要了解它所有的很有方向指导意义的结论。

习题6.5-8
给出一个时间为O(nlgk)的算法,用来将k个已排序链表合并为一个排序链表的算法。n为所有输入链表中元素的总和。
1、算法说明。
如果先选2个链表合并,原来的k个链表变成k-1个链表,对余下的k-1个链表采取同样的策略,知道所有的链表合并为一个为止。这个办法很简单,但是时间性能不好。很容易知道,k个已排序链表中的两个合并的时间最大为2(n/k)。这样总代价为O(nk)。达不到要求。
采用这样的办法A1:
1)、将k个链表的首元素取出,建立一个k个元素的最小堆(或最大堆)。
2)、堆顶的元素为最值,将堆顶元素取走,并将堆顶元素原来所在链表的首元素放到堆顶,然后调整新堆使其满足堆得性质(时间代价为O(lgk))。
3)、重复步骤2)n次,直到道原来的k个链表变成空链表。
很容易分析出A1的时间代价为O(nlgk)