@louisyw
2015-11-24T21:03:06.000000Z
字数 3889
阅读 1408
算法
title: 摊还分析
categories: 数据结构与算法
在摊还分析中,我们通过求数据结构中一个操作序列中所执行的所有操作的平均时间,来评价操作的代价。
栈有两个基本操作
PUSH(S, x):将对象x压入栈S中。
POP(S): 将栈S的栈顶元素弹出,并返回该对象。对空栈执行此操作会报错。
上述两个操作都是O(1)时间,假定花费为1。因此一个n个PUSH和POP操作的写列的总代价为n,而n个操作的实际运行时间为
现增加一个新的操作MULTIPOP(S,k),它删除栈S栈顶的k个对象,如果栈中对象少于k,则将整个栈的内容都弹出。
分析由n个PUSH、POP和MULTIPOP组成的操作序列在一个空栈上的执行情况。虽然一个MULTIPOP操作的代价可能更很高,但是均摊下来,上述操作序列的代价至多是
特别注意的是,当在栈中继续增加一个MULTIPUSH操作时,此时的均摊代价已不是
k位二进制计数器,计数器的初始值为0.用位数组
INCREMENT(A)
i = 0
whil i < A.length and A[I] == 1
A[i] = 0
i = i+1
if i < A.length
A[i] = 1
加1操作中各位置上的变化如下表:
计数器值 | A[7] | A[6] | A[5] | A[4] | A[3] | A[2] | A[1] | A[0] | 每步代价 | 总代价 |
---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
2 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 2 | 3 |
3 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 4 |
4 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 3 | 7 |
5 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 8 |
6 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 2 | 10 |
7 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 11 |
8 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 4 | 15 |
9 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 16 |
10 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 2 | 18 |
11 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 1 | 19 |
12 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 3 | 22 |
13 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 23 |
14 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 2 | 25 |
15 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 26 |
16 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 5 | 31 |
对于一个初值为0,执行n次INCREMENT操作,显然,A[0]位变化n次,A[1]位变化
在核算法中,对不同的操作赋予不同的费用,赋予某些操作的费用可能大于或等于实际操作的代价。将赋予一个操作的费用称为摊还代价。当一个操作的摊还代价爱超出其市集代价时,我们将差额存入数据结构中的特定对象,存入的差额被成为信用。对于后续操作中摊还代价小于市集代价的情况,信用可以用来支付差额。
当表的容量翻倍时
1 | |||||||||||||||
0 | 2 | ||||||||||||||
0 | 0 | 2 | 2 | ||||||||||||
0 | 0 | 0 | 0 | 2 | 2 | 2 | 2 | ||||||||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
将银行结余表示为势,势能的释放用来支付未来的操作。
+ 数据结构开始于
+ 第i次操作,变化为
+ 定义势能函数
摊还代价
如果
如果
n次操作的总的摊还代价为
现举例说明:
定义