算法导论--平摊分析之聚集分析

在平摊分析中,执行一系列数据结构操作所需要的时间是通过对执行的所有操作求平均而得出的。

平摊分析可以用来证明在一系列操作中,通过对所有操作求平均之后,即使其中单一的操作具有较大的代价,平均代价还是很小的。平摊分析与平均情况分析的不同之处在于它不牵涉到概率;平摊分析保证在最坏情况下,每个操作具有平均性能。

聚集分析

在聚集分析中,要证明对所有的n,由n个操作所构成的序列的总时间在最坏情况下为T(n)。因此,在最坏情况下,每个操作的平均代价(或称平摊分析)为T(n)/n。请注意这个平摊代价对每个操作都是成立的,即使当序列中存在几种类型的操作时也是一样的。

栈操作

 在关于聚集分析的第一个例子中,我们要分析增加了一个新操作后的栈。有两种基本的栈操作,每种操作的时间代价都是O(1):

PUSH(S,x):将对象x压入栈S。

POP(S):弹出S的栈顶返回弹出的对象。

因为这两个操作的运行时间都为O(1),故可以把每个操作的代价都视为1。因此,含n个PUSH和POP操作的序列的总代价为n,而这n个操作的实际运行时间就是O(n)。

现在我们增加一个栈操作MULTIPOP(S,k),它的作用是弹出栈S的k个栈顶对象,或者,当栈包含少于k个对象时,弹出整个栈中的数据对象。

当MULTIPOP(S,s)对一个包含s个对象的栈操作时,运行时间是多少?实际的运行时间与实际执行的POP操作数成线性关系,因而只要按PUSH和POP具有抽象代价1来分析MULTIPOP就足够了。while循环迭代的次数是从栈中弹出的对象个数min(s,k)。对循环的每次迭代,都要调用一次POP。因此,MULTIPOP的总代价是min(s,k),而实际运行时间则为这个代价的一个线性函数。

现在来分析一个由n个PUSH,POP和MULTIPOP操作构成的序列,其作用于一个初始为空的栈。序列中一次MULTIPOP操作的最坏情况代价为O(n),因为栈的大小至多为n。因此,任意栈操作的最坏情况时间就是O(n),因此n个操作的序列的代价是O(n^2),因为可能会有O(n)个MULTIPOP操作,每个的代价都是O(n)。虽然这一分析是正确的,但通过单独地考虑每个操作的最坏情况代价而得到的O(n^2)结论却是不够紧确的。

利用聚集分析,我们可以获得一个考虑到n个操作的整个序列的更好的上界。事实上,虽然一次MULTIPOP操作的代价可能较高,但当作用于一个初始为空的栈上时,任意一个包含n个PUSH,POP和MULTIPOP操作的序列其代价至多为O(n)。为什么会是这样呢?一个对象在每次被压入栈后,至多被弹出一次。所以,在一个非空栈上,调用POP的次数(包括在MULTIPOP的调用)至多等于PUSH操作的次数,即至多为n。对任意的n值,包含n个PUSH,POP和MULTIPOP操作的序列的总时间为O(n)。每个操作的平均代价为O(n)/n=O(1)。在聚集分析中,我们把每个操作的平摊代价指派为平均代价。所以在这个例子中,三个栈操作的平摊代价都是O(1)。

我们再一次强调,虽然已经说明一个栈操作的平均代价和运行时间是O(1),但没有用到概率推理。实际上,我们给出的是一列n个操作的最坏情况界O(n)。用n除这个总代价可得每个操作的平均代价,亦即平摊代价。

posted @ 2016-12-19 11:14  是非猫  阅读(1862)  评论(0编辑  收藏  举报