算法导论习题解-第17章摊还分析

总结

记账法

相当于每月领取一定的零花钱,用来支付实际费用,只要在任何时候余额不为负。那么总花费一定不超过总的零花钱。必须条件,同时也是缺点:任何时候余额不为负。

势能法

条件比记账法宽松。对于数据结构的每个状态,定义一个势能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)

你可能感兴趣的:(算法)