《算法(第四版)》 1.4.8.5 节“均摊分析”中有这样一个命题:
命题 E 。在基于可调整大小的数组实现的 Stack 数据结构中(请见算法 1.1 ),对空数据结构所进行的任意操作序列对数组的平均访问次数在最坏情况下均为常数。
Proposition E. In the resizing array implementation of Stack (Algorithm 1.1), the average number of array accesses for any sequence of operations starting from an empty data structure is constant in the worst case.
随后给出的简略证明为:
对于每次使数组大小增加(假设大小从 N 变为 2N )的 push()操作,对于 N/2+2 到 N 之间的任意 k ,考虑使栈大小增长到 k 的最近 N/2-1 次 push()操作。将使数组长度加倍所需的 4N 次访问和所有 push()操作所需的 N/2 次数组访问(每次 push()操作均需访问一次数组)取平均,我们可以得到每次操作的平均成本为 9 次数组访问。
Proof sketch: For each push() that causes the array to grow (say from size N to size 2N), consider the N/2 1 push() operations that most recently caused the stack size to grow to k, for k from N/2 + 2 to N. Averaging the 4N array accesses to grow the array with N/2 array accesses (one for each push), we get an average cost of 9 array accesses per operation.
简单来说,我看不懂这个证明,能否帮忙解释一下?任何想法或提示都可能有帮助,谢谢。
算法 1.1:
import java.util.Iterator;
public class ResizingArrayStack<Item> implements Iterable<Item>
{
private Item[] a = (Item[]) new Object[1]; // 栈元素
private int N = 0; // 元素数量
public boolean isEmpty() { return N == 0; }
public int size() { return N; }
private void resize(int max)
{ // 将栈移动到一个大小为 max 的新数组
Item[] temp = (Item[]) new Object[max];
for (int i = 0; i < N; i++)
temp[i] = a[i];
a = temp;
}
public void push(Item item)
{ // 将元素添加到栈顶
if (N == a.length) resize(2 * a.length);
a[N++] = item;
}
public Item pop()
{ // 从栈顶删除元素
Item item = a[--N];
a[N] = null; // 避免对象游离(请见 1.3.2.4 节)
if (N > 0 && N == a.length/4) resize(a.length/2);
return item;
}
public Iterator < Item > iterator()
{ return new ReverseArrayIterator(); }
private class ReverseArrayIterator implements Iterator<Item>
{ // 支持后进先出的迭代
private int i = N;
public boolean hasNext() { return i > 0; }
public Item next() { return a[--i]; }
public void remove() { }
}
}
