本周的内容是Amortized Analysis,是对算法复杂度的另一种分析。它的基本概念是,给定一连串操作,大部分的操作是非常廉价的,有极少的操作可能非常昂贵,因此一个标准的最坏分析可能过于消极了。因此,其基本理念在于,当昂贵的操作特别少的时候,他们的成本可能会均摊到所有的操作上。如果人工均摊的花销仍然便宜的话,对于整个序列的操作我们将有一个更加严格的约束。本质上,均摊分析就是在最坏的场景下,对于一连串操作给出一个更加严格约束的一种策略。
均摊分析与平均情况分析的区别在于,平均情况分析是平均所有的输入,比如,INSERTION SORT算法对于所有可能的输入在平均情况下表现性能不错就算它在某些输入下表现性能是非常差的。而均摊分析是平均操作,比如,TABLEINSERTION算法在所有的操作上平均表现性能很好尽管一些操作非常耗时。在均摊分析中,不涉及概率,并且保证在最坏情况下每一个操作的平均性能。
有三类比较常见的均摊分析:
1.聚类分析:证明对所有的n,由n个操作所构成的序列的总时间在最坏情况下为T(n),每一个操作的平均成本为T(n)/n;比如栈的操作,对于一个空栈的入栈和出栈的操作
2.记账方法:在平摊分析的记帐方法中,决定每一个操作的均摊成本,对不同的操作赋予不同的费用,某些操作的费用比它们的实际代价或多或少。我们对一个操作的收费的数量称为平摊代价。当一个操作的平摊代价超过了它的实际代价时,两者的差值就被当作存款(credit),并赋予数据结构中的一些特定对象,可以用来补偿那些平摊代价低于其实际代价的操作。这种方法与聚集分析不同的是,对后者,所有操作都具有相同的平摊代价。数据结构中存储的总存款等于总的平摊代价和总的实际代价之差。注意:总存款不能是负的。在开始阶段对于过度要价存储预先支付的存款,在后面的序列中再支付操作。比如,二进制计数器: 通过二进制触发器计算一系列数字
3.势能方法:在平摊分析中,势能方法(potential method)不是将已预付的工作作为存在数据结构特定对象中存款来表示,而是将存款总体上表示成一种“势能”或“势”,它在需要时可以释放出来,以支付后面的操作。势是与整个数据结构而不是其中的个别对象发生联系的。比如,动态表,可以动态改变大小的连续存储数组。
一、聚类分析
在聚类分析中,对于一连串的n的操作,我们计算总的最坏时间T(n). 在最坏情况下,每一个操作的平均成本或者均摊成本是T(n)/n. 成本T(n)/n适用于每一个操作(可能有几种类型的操作)。另外两种方法可能将不同的均摊成本分配给不同类型的操作。
比如,有MULTIPOP操作的栈。有两种基本的栈操作都分别花费O(1)的时间: PUSH(S,x)和POP(S)分别是将对象x压入栈中,从栈S的顶部弹出并返回弹出的对象。将每一个操作的花销都赋为1. 一连串n个PUSH和POP操作的总消耗为n,对于n个操作的实际运行时间为O(n).
现在添加一个额外的栈操作MULTIPOP。MULTIPOP(S,k) 是弹出栈S的前k个对象(或者弹出整个栈如果k大于栈的大小的话)。
MULTIPOP的总消耗是min{|S|,k}.
现在考虑在一个初始为空的栈上的一序列n个POP,PUSH和MULTIPOP操作。算法伪代码如下:
下面为一个例子:
粗略地分析,MULTIPOP (S,k)将会花费O(n)的时间,因此,
在操作序列中,一些操作可能会很廉价,但是一些操作可能会非常昂贵耗时,比如MULTIPOP(S,k). 然而,最坏的操作往往不是经常被调用的。因此,传统的最坏的单一操作分析会给出过于消极的边界。
我们的目标是,对于每一个操作,我们希望能够赋予其一个均摊的成本来对实际的总的成本进行定界。对于n个操作的任意序列,我们有
这里,是表示第i步的实际成本。
使用聚类分析使得有更加紧凑的边界分析,对于所有的操作都有相同的均摊成本.
观察得知,POP操作的数目一定小于或者等于PUSH操作的数目。因此,我们可以得到: