先通过表的扩增这一例子来引入今天的主题——平摊分析和势能分析
一个哈希表的大小应该为多少比较合适?
theta(n)比较合适
可是万一我们不知道n是多大呢
使用动态表解决 溢出就建立一个大小翻倍的空间,然后复制过去
这样做插入的最坏时间复杂度为n
让我们看看平均的时间复杂度,每次基本插入操作为1,空间溢出时需要开一个更大一倍的空间,并复制当前的元素过去,所以空间溢出时所需要的时间为2的i次方(i为第几次溢出)
所以其真实的时间消耗为n+sigma(2^i) 0<=i<=lg(n+1) 即3n
因此其实插入的时间复杂度为O(1)
尽管有时会有巨大开销,但是会被平均的开销平摊掉,这就是平摊分析
平摊分析:平均操作复杂度不高,尽管有些操作会有较高的复杂度
三种类型的平摊方法:
1.聚集分析
2.记账方法(accounting)
3.势能分析
2.3它们为每一个操作分配了特点的平摊代价
记账方法:
想象自己担任了一个会记
对第i个操作收费为ci
收益个虚构的平摊代价
每一步运算需要花费1$
未用到的余款就被存到银行,用于偿付以后的操作
如每次插入收费为3,插入消耗1,剩下的2存入银行为表翻倍时做准备,要始终保证银行的金额为正
即提前平摊,总能支付扩充表的费用,这样某一个高开销的操作会被平摊掉
势能方法:
算法分析里最漂亮的产物之一
刚开始数据结构状态为D0
操作i的代价为ci
操作i可以看作把数据结构由Di-1转化为Di
定义势能函数
将数据结构的集合定位实数值
D0 = 0 初始的势为0
所有Di >=0,我们不能让势低于0
定义平摊代价为Ai,对势能Di有Ai=Ci+Di-Di-1
Di-Di-1 部分是势能的改变量,如果其>=0 那么Ai>ci 我收取的费用超过了实际的花费,即操作i储存了后面数据结构所需的功
如果势能的改变量<0,即我们用存储的势能转化为能量来帮助完成操作i
记账方法考虑的是平摊代价
而势能分析考虑的是银行存款(存储势能)
有sigmaAi=sigma(ci+Di-Di-1)=sigma(ci+Dn-D0)
D0为0,Dn大于等于0,所以左边大于右边,是实际代价的一个上界
我们再次以表的扩增为例感受一下势能分析
我们的势能函数为2i-2^ceil(lgi)
如何推导出这样的势能函数的?
定义势能函数难度低于定义平摊代价
Di>=0
第i个操作的平摊代价Ai=Ci+Di-Di-1= i+2i-2^ceil(lgi)-(2i-2-2^ceil(lgi-1))(刚好i是2的幂)
1+2i-2^ceil(lgi)-(2i-2-2^ceil(lgi-1))
case1 i-1是2的幂,那么Ai=i+2-2(i-1)+(i-1)=3
case2 i-1不是2的幂 那么Ai=1+2i-2^ceil(lgi)-(2i-2-2^ceil(lgi-1))=3
这样得到的平摊代价也为3
不关注实时性能只关注聚集性能