算法分析方法之分摊分析(合计方法,记账方法,势能方法)

一、合计方法

合计方法顾名思义,就是把前n个方程所需要的费用加起来,然后再把这个加起来的数÷n即可。

例1:建立一个动态的数组,初始长度为1。每次都插入一个数,而当长度为k的数组插入k+1个数时,会开辟一个新的2k的数组。插入数字的消费记作1,而将数字从旧数组移动到新数组也记作1。所以插入每个数的消费分别为:

第1个数:1

第2个数:2  数组开辟到2

第3个数:3  数组开辟到4

第4个数:1

第5个数:5  数组开辟到8

第6、7、8个数:1

……

求插入每个数字的平均算法复杂度。

很容易能看出,插入每个数所需的话费分别为:

\left\{\begin{matrix} 1 ,x\neq 2^k + 1(k = 0,1,2...) \\ x ,x = 2^k+1 (k = 0,1,2...) \end{matrix}\right.

由此,插入前n个数的合计消费为:

n + \sum _{i = 1} ^{\[lgn\]}(i-1) \leqslant n + 2n = 3n = O(n)

因此最终答案为O(n)/n=O(1)

可以看出:合计方法只要知道每次行动究竟耗费多少,那么就能找出它的总和来。剩下的就是用不等式去掉取整部分等问题了。

二、记账方法

记账方法的核心就是给部分步骤每一步安排多余的费用,在其余的步骤中支付这些多余的费用。至于费用的具体安排需要自己寻找,安排费用的最终目标是将不均匀的操作分到均匀的操作里面。

还是以上面的例题为例,不均匀的操作为扩大数组后各个数字的复制,均匀的操作为每个新数字的插入。

我们令每个新数字的插入消费为3(这个数字需要自己想,可以借助之前的合计方法)。自己插入先消耗一个。然后在插入他之后第一次扩张数组时,一个用于自己插入,另一个用于前半段的自己插入。这样就能把不均匀的分配到均匀之中。

为了加深理解,再来一个例题

例2:有一个2进制计数器,某位从1变成0或从0变成1的花费记作1,那么求每次加1时算法消耗的平均复杂度。

 在这里,只要计算几次就会发现:每加一次必定会有一个位变1,而变0的位则不固定。所以令1消费2,1变回0抵消掉1的消费,那么复杂度就是2n,也就是O(n)。

综上所述,记账方法的过程是把均匀的操作的消费增加一些,之后不均匀的操作用均匀的操作中和掉,从而得到平均分摊的效果。

三、势能方法

势能方法是在正常的计算中添加一个势能函数Φ。如果把记账方法用每一步提前存储一些钱来描述的话,势能方法的Φ就是一个总的大存钱罐。当平均消费较低时Φ就多存一些,平均消费较高时就从Φ取,以达到平均的效果。即消费低时Φ增加,消费高时Φ减小

以例1为例,在这里很明显不是2^k+1时 ,消费较少需要存,根据合计方法的经验,先存个2,然后在2^k+1时,把存的基本上全取出来,那就剩0,以这个为基本思想,那么最初定义公式为

\phi = \left\{\begin{matrix} 0, x=2^k+1 \\ \phi (x-1)+2,x\neq 2^k+1 \end{matrix}\right.

那么分开讨论,当x \neq 2^k+1

加了势能变化的消费为  \phi(x) - \phi(x - 1) + 2 = 3

x = 2 ^ k + 1

加了势能变化的消费为  

\phi(x) - \phi(x - 1) + 2^k+1 = -2(2^k + 1 - 2 ^ {k-1} - 1) + 2 ^ k+1 = 1(2^k = x)

可以看出两种情况下加了势能变化的消费都是常数,所以是O(1)

那么对于势能函数\phi = 2\times numbers - size(numbers指插入的数字数,size指动态数组大小),也是相同的处理情况,最后算出来结果也是O(1),这里不在赘述。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值