【数学】平摊分析与动态表问题

普通的动态表问题

我们需要用一个数据结构存储一些数据,但并不知道数据有多少个,所以也不知道申请多少空间合适。因此,我们采取了动态申请空间的策略,假设现在表的大小为 s i z e size size,数据数为 n u m num num
n u m < s i z e num<size num<size时需要添加一个数据,直接加入即可,单次操作复杂度为1。
n u m = s i z e num=size num=size时需要添加一个数据,则申请一个大小为 2 s i z e 2size 2size的空间,然后将原来的 n u m num num个数加上新加的数据都放进新空间里,复杂度为 n u m + 1 num+1 num+1
假设插入 n n n次,那么这样一个数据结构的均摊复杂度是多少呢?

朴素的分析是,单次操作是 O ( n ) O(n) O(n)的,操作数是 O ( n ) O(n) O(n)的,所以是 O ( n 2 ) O(n^2) O(n2)
这是一个很松的上界,可以做更好的估计。

采用聚集分析的话,当 i − 1 i-1 i1为2的次幂时, c i = i c_i=i ci=i。其他时候 c i = 1 c_i=1 ci=1
所以总代价 ∑ i = 0 n c i ≤ n + ∑ i = 1 ⌊ log ⁡ n ⌋ 2 i ≤ 3 n \sum_{i=0}^nc_i \leq n+\sum_{i=1}^{\lfloor \log n \rfloor} 2^i \leq 3n i=0ncin+i=1logn2i3n
平摊代价 3 n n = 3 \frac{3n}{n}=3 n3n=3

有了这个启发后,我们还可以设计记账法来分析。
一次插入的记账为3,其中1的代价给这次新插的数用,1的代价存款在新插的数上,1的代价给一个没有存款的数据。一次扩张后到下一次扩张前,新插的数据的个数和旧的数据个数是相等的,所以每次扩张时,动态表内的所有数上均有1的存款,那么换空间的复杂度只需要消耗这些存款了。

最后,考虑势函数法。
决定势函数的只有两个东西, s i z e size size n u m num num,不妨先待定系数,设 Φ ( T ) = a n u m + b s i z e \Phi(T)=anum+bsize Φ(T)=anum+bsize
首先,我们考虑触发表扩张的一个操作,需要让它的平摊代价为常数。这里的 n u m num num s i z e size size设为添加新数据前的:
a i = c i + Φ ( T i ) − Φ ( T i − 1 ) = n u m + 1 + ( a ( n u m + 1 ) + b ( 2 s i z e ) ) − ( a n u m + b s i z e ) = n u m + 1 + a + b s i z e a_i=c_i+\Phi(T_i)-\Phi(T_{i-1})=num+1+(a(num+1)+b(2size))-(anum+bsize)=num+1+a+bsize ai=ci+Φ(Ti)Φ(Ti1)=num+1+(a(num+1)+b(2size))(anum+bsize)=num+1+a+bsize
扩张前应该有 n u m = s i z e num=size num=size,所以 b = − 1 b=-1 b=1时是常数。
至于这个常数是多少,其实我们用聚集分析和记账法已经算出来了,是3,所以 a = 2 a=2 a=2
得到势函数: Φ ( T ) = 2 n u m − s i z e \Phi(T)=2num-size Φ(T)=2numsize
验证一下不扩张的情况: a i = 1 + ( 2 n u m + 2 − s i z e ) − ( 2 n u m − s i z e ) = 3 a_i=1+(2num+2-size)-(2num-size)=3 ai=1+(2num+2size)(2numsize)=3
完美!

带删除的动态表问题

在上面的例子看起来,我们可以利用聚集分析和记账法完成,势函数显得有些没必要。但这个问题升级一下,前两种方法就不是那么好用了。

假设我们的动态表中的数据可以被删除,则这个表可能也需要收缩。既然我们扩张都是2的倍数,那当然收缩也收缩成 1 2 \frac{1}{2} 21比较好。
定义装载率 α = n u m s i z e \alpha=\frac{num}{size} α=sizenum,什么时候收缩呢?
如果是 α = 1 2 \alpha=\frac{1}{2} α=21时收缩,则可能出现一种情况,删除和插入交错进行,表的大小反复横跳。所以我们会定一个值,比如说 α 0 = 1 4 \alpha_0=\frac{1}{4} α0=41时收缩。

势函数不应该小于0,所以应该分两段(这里以 1 2 \frac{1}{2} 21分段是因为扩张和收缩的分界点都是2次幂,如果是3次幂扩张等情况则应该不同考虑)来设计:
Φ ( T ) = { a n u m + b s i z e α ≥ 1 2 c n u m + d s i z e α < 1 2 \Phi(T)=\begin{cases}anum+bsize & \alpha \geq \frac{1}{2} \\ cnum+dsize & \alpha < \frac{1}{2} \end{cases} Φ(T)={anum+bsizecnum+dsizeα21α<21

1 2 \frac{1}{2} 21处势函数应该连续,所以:
a n u m + 2 b n u m = c n u m + 2 d n u m anum+2bnum=cnum+2dnum anum+2bnum=cnum+2dnum 2 ( d − b ) = a − c 2(d-b)=a-c 2(db)=ac
构造型待定系数的解往往不止一种,不妨让 b = − 1 2 a , d = − 1 2 d b=-\frac{1}{2}a,d=-\frac{1}{2}d b=21a,d=21d
接下来就是保证扩张和收缩的时刻的平摊代价都是常数。

扩张时:
n u m + 1 + ( a n u m + a + 2 b s i z e ) − ( a n u m + b s i z e ) num+1+(anum+a+2bsize)-(anum+bsize) num+1+(anum+a+2bsize)(anum+bsize),如前面一样的式子,可以解出 b = − 1 b=-1 b=1所以 a = 2 a=2 a=2
收缩时:
n u m + 1 + ( c n u m − c + 1 2 d s i z e ) − ( c n u m + d s i z e ) num+1+(cnum-c+\frac{1}{2}dsize)-(cnum+dsize) num+1+(cnumc+21dsize)(cnum+dsize),将 α 0 = 1 4 \alpha_0=\frac{1}{4} α0=41代入得 d = 1 2 d=\frac{1}{2} d=21

最终设计的势函数:
Φ ( T ) = { 2 n u m − s i z e α ≥ 1 2 1 2 s i z e − n u m α < 1 2 \Phi(T)=\begin{cases}2num-size & \alpha \geq \frac{1}{2} \\ \frac{1}{2}size-num & \alpha < \frac{1}{2} \end{cases} Φ(T)={2numsize21sizenumα21α<21

知晓了势函数的设计原理后,即使问题继续变化,我们还是很好设计势函数。例如 α 0 = 1 3 \alpha_0=\frac{1}{3} α0=31时收缩呢?只需要在解收缩时的势函数方程时稍加变动。

首先,若 α 0 = 1 3 \alpha_0=\frac{1}{3} α0=31时收缩,收缩后 α = 2 3 > 1 2 \alpha=\frac{2}{3}>\frac{1}{2} α=32>21,所以:
c i = n u m + 1 + ( 2 n u m − 2 − 1 2 s i z e ) − ( d s i z e − 2 d n u m ) = ( 3 + 2 d ) n u m − ( 1 2 + d ) s i z e − 2 c_i=num+1+(2num-2-\frac{1}{2}size)-(dsize-2dnum)=(3+2d)num-(\frac{1}{2}+d)size-2 ci=num+1+(2num221size)(dsize2dnum)=(3+2d)num(21+d)size2
s i z e = 3 n u m size=3num size=3num代入,解得 d = 3 2 d=\frac{3}{2} d=23,故 c = − 3 c=-3 c=3

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值