普通的动态表问题
我们需要用一个数据结构存储一些数据,但并不知道数据有多少个,所以也不知道申请多少空间合适。因此,我们采取了动态申请空间的策略,假设现在表的大小为sizesizesize,数据数为numnumnum。
若num<sizenum<sizenum<size时需要添加一个数据,直接加入即可,单次操作复杂度为1。
当num=sizenum=sizenum=size时需要添加一个数据,则申请一个大小为2size2size2size的空间,然后将原来的numnumnum个数加上新加的数据都放进新空间里,复杂度为num+1num+1num+1。
假设插入nnn次,那么这样一个数据结构的均摊复杂度是多少呢?
朴素的分析是,单次操作是O(n)O(n)O(n)的,操作数是O(n)O(n)O(n)的,所以是O(n2)O(n^2)O(n2)。
这是一个很松的上界,可以做更好的估计。
采用聚集分析的话,当i−1i-1i−1为2的次幂时,ci=ic_i=ici=i。其他时候ci=1c_i=1ci=1。
所以总代价∑i=0nci≤n+∑i=1⌊logn⌋2i≤3n\sum_{i=0}^nc_i \leq n+\sum_{i=1}^{\lfloor \log n \rfloor} 2^i \leq 3n∑i=0nci≤n+∑i=1⌊logn⌋2i≤3n
平摊代价3nn=3\frac{3n}{n}=3n3n=3。
有了这个启发后,我们还可以设计记账法来分析。
一次插入的记账为3,其中1的代价给这次新插的数用,1的代价存款在新插的数上,1的代价给一个没有存款的数据。一次扩张后到下一次扩张前,新插的数据的个数和旧的数据个数是相等的,所以每次扩张时,动态表内的所有数上均有1的存款,那么换空间的复杂度只需要消耗这些存款了。
最后,考虑势函数法。
决定势函数的只有两个东西,sizesizesize和numnumnum,不妨先待定系数,设Φ(T)=anum+bsize\Phi(T)=anum+bsizeΦ(T)=anum+bsize
首先,我们考虑触发表扩张的一个操作,需要让它的平摊代价为常数。这里的numnumnum和sizesizesize设为添加新数据前的:

本文探讨了动态表的插入策略,通过聚集分析、记账法和势函数法,计算了均摊复杂度。随后扩展到带删除操作的场景,设计了针对装载率的势函数,解决了数据膨胀和收缩的问题。
最低0.47元/天 解锁文章
4693





