总结
记账法
相当于每月领取一定的零花钱,用来支付实际费用,只要在任何时候余额不为负。那么总花费一定不超过总的零花钱。必须条件,同时也是缺点:任何时候余额不为负。
势能法
条件比记账法宽松。对于数据结构的每个状态,定义一个势能P(i),第i步操作的摊还代价记为A[i] = c[i] + P(i)-P(i-1),只要P(n) >= P(0),摊还代价就不会超过实际代价。即用前面积累起来的势能支付后面代价较大的操作。
习题编号以第三版为准。
#17.3-2 动态扩张表
对一个数据结构执行由n个操作组成的序列,当i为2的幂时,第i个操作的代价为i,否则为1。分别使用聚合分析(#17.1-3),记账法(#17.2-2)和势能法(#17.3-2)分析摊还代价。
解:实际就是动态扩张表,当容量为2的幂时,容量加倍。见课本17.4节对动态表的分析。记账法:每个操作摊还代价记为3。势能法:Potential(i) = 2*(i-maxP2)其中maxP2是不超过i的最大的2的幂,比如Potential(8)=0, Potential(9)=2, ... Potential(15)=14
#17-1 位逆序的二进制计数器
解:实际就是通过位操作实现课本中的二进制计数器,只不过自增是从左向右进行而不是从右向左。由课本中的分析可知,自增操作的平摊代价为O(1)。普通计数器代码如下:
public class Counter {
public static int increase(int n) {
int b = 1;
while((n|b) == n) {
n &= ~b;
b <<= 1;
}
n |= b;
return n;
}
public static void main(String[] args) {
int n = 0;
for(int i=0; i<16; i++) {
System.out.println(n);
n = increase(n);
}
}
}
#17-2 动态二分查找
见instructor's manual
#17-3 摊还加权平衡树
解:(d) 设左子树大小为a*n,右子树为(1-a)*n,则势能P(n) >= c(a*n - (1-a)*n),由于平衡的成本为n,只需P(n) > n那么就可以用势能支付平衡成本。即c > 1/(2*a - 1)
(e) 假设插入后不需要重新平衡,插入成本lg(n),插入后势能的变化最多为2*lg(n),因为只有在插入的路径上Δ才会变化,每个节点最多变化2,故平摊成本为O(lg n)。假设需要平衡,则插入及平衡成本为lg(n)+n,势能变化为P(n)-P(n-1) = 0 - P(n-1) < 0 - c(2*a-1)*n = -n,故平摊成本为 lg(n)+n+P(n)-P(n-1) < lg(n)+n-n = lg(n)
本文详细介绍了算法导论中第17章关于摊还分析的内容,包括记账法和势能法的概念,并对动态扩张表、位逆序二进制计数器、动态二分查找和摊还加权平衡树等习题进行了解答。通过实例分析了不同方法下的摊还代价,揭示了动态数据结构在不同操作下的平摊复杂度。
6230

被折叠的 条评论
为什么被折叠?



