算法设计:平摊分析

平摊分析是怎么一回事?:

感觉好像和当初求快速排序的平均复杂度是类似的?但其实不是:

不涉及概率的话,那就和当初求快排期望不一样了。

那么这个研究方法是什么?:聚集方法,会计方法,势能算法。

 聚集方法:

这个平均是直接的,简单的,不管是哪一步。 

举个例子:

现在我有一个函数:

可以看到, 

现在,我们来考虑这个问题:

我们有n个操作,那么最坏复杂度是什么情况?全部都是muitpop?mulipop的复杂度最大是n,那最终T(n)=n*n?明显太大了!

所以:

全是pop push 就是n,有了mulipop就变大,最可怕的情况是没有pop,全是mulipop,那也只有2n。

另一个例子:二进制计算器:

要给x加一,也就是说,低位数1的变成0,一直往上,直到看到0,就把它变成1,然后就结束了。 

 

但这样算也太粗糙了,我们要精细些:

我们可以发现,第一列(A[0])每次加1都要改一次,第二列每加两次就改一次,第三列每加4次就改一次····现在加了n次,那A[0]位就改了n次,A[1]位改了n/2次····可以发现

 这和10进制加法是一个道理。我们给一个10进制数加1,第一位数每次都会变化,但十位要加10次才会变,百位要100次才会变。

 (等等,i最大不应该是log2k吗?ppt写错了。)

总而言之,就是把总的复杂度算出来(都是可以明确算出来小于什么的)在除以总操作数。

现在来讲讲会计方法:

举个例子:

有多少push就有多少pop,因此直接给他2块钱,各式各样的Pop就不管了。

接下来开始分析:

push平摊的代价有2,因此每次都会存一点“钱”,pop的时候,就会花掉这些钱。可以发现,栈里有多少可以pop出来的元素,就会有多少钱存着,因此永远都不会破产。

还有一个例子:

这样定义是不是特别好?反正每次加1都只会发生一次0-1反转,这样好算多了。

 

简单说,就是:进行了n次操作,也就有n次0-1变化,交了2n块钱。当然这些钱可能没全花掉,多交了,所以说是上界为2n

势能分析:

咋一看好像和会计法没什么区别?

现在的问题是:势能函数究竟是什么鬼?:

注意:势能只要比初始值大就可以了,中间可以变小。这里因为拿“栈中剩余的元素”作为势能,和会计法的存款正好一样多,所以很像,但不一样。可以看出,势能法更加自由一些,可以设置为更大的值,只要势能不小于0就不算翻车。

下面这个例子相信你也已经猜到了:

拿1的个数作为势能函数,很好地符合了要求。可以直接在这里分析:每次加一的时候,开头的t个1变成0加上最后0变1就是全部的操作了,这时减少了1的个数t-1(减少t个1的同时又加了一个1),最后平摊的代价也就只有2.

 当然假如初始值不是0怎么办?:

就是把Ci放到另一边,接下来也就是一样的(其实不换不也看得出来吗?就是把开头的势能换成b0呗):

现在再来讲一讲动态表:

这里要解释一下:空表的大小为0,规定此时装载因子为1. 

 现在要扩张表了怎么办?:

遇到装不下的情况就翻一倍。现在可以看到,假如表装得下,操作复杂度就是1;假如装不下,那就要是原本的元素数加1.

现在具体分析:

聚集分析:

假如要用会计法呢?:

“没有存款的数据”是什么?下面解释一下:

就是这样:每次扩张的时候,以前的老数据会花掉自己的存款,那下次扩张怎么办?就让后来的新元素来帮他们存,这样等到下次扩张的时候,以前用掉了存款的老元素存款又都回来了。这样总不会负债。

接下来就是势能法了。 

这样,当没有扩表的时候,Ci=1+2=3,在扩表时Ci=size[T](之前的size)+1+(2(现在的势能)-size(T)(也是之前的))=3 

刚刚一直是在扩表,现在要缩表怎么办?:

假如把界限设为1/2的话,想象一下:我刚刚扩完表,数量是1/2多一个,只要再删一次就要又缩一遍,这不神经病吗?所以要变成1/4比较好。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值