簡單理解算法篇--攤還分析


    攤還分析是用來評價程序中的一個操作序列的平均代價,有時可能某個操作的代價特別高,但總體上來看也並非那么糟糕,可以形象的理解為把高代價的操作“分攤”到其他操作上去了,要求的就是均勻分攤后的平均代價。

 攤還分析有三種常用的技術;聚合分析,核算法,勢能法。

 首先看個例子,現在有三種操作,push(s),pop(s),mutlipop(s,k),push(s),統稱為棧操作 push(s)每次只能壓一個數據,所以規定操作的代價為1pop(s)每次只能彈一個數據,所以也規定操作的代價為1,而mutlipop(s,k),內部實現的是一個循環彈出,每執行一次的代價為kk<n,n為棧的最大容量)。那么現在問題來了,我想分析下執行n棧操作最壞情況下的時間復雜度是多少?第一反應應該就是這樣想的,mutlipop(s,k)的代價最高,最高位k=n;

執行n次的最壞情況當然就是o(n2)啦,當實際上並非如此。

 

 聚合分析要求我們要總體看問題,首先mutlipop(s,k)也是個彈棧的操作,當棧里有數據的時候才執行有效,所以上述提到的o(n2)是不科學的,而push(s),pop(s)的代價是1,可想而知最壞的情況當然是前n-1次操作都是壓棧,而最后一次才執行mutlipop(s,n-1),這樣的代價也只有2n-2,時間復雜度為o(n),平均下來每個操作的攤還代價就為o(1)了。

 

 核算法比較好理解,進行攤還分析時,攤還的代價有可能多於實際的代價,也有可能少於實際的代價,多於實際代價的差額會存進一個數據結構中,稱為信用,而當遇到少於實際代價的時候就可以用這些信用來填充了。注意這些什么算法提供的只是思路,求出一系列操作代價的上界的思路,具體的做法還是要自己思考的。

 同樣是壓棧的例子,我們可以賦給Push(s)操作的攤還代價是2,相當於自己使用了1,而壓進去的必定會彈出,剩下的1就作為彈出時的費用,這樣pop(s)mutlipop(s,k)的攤還代價就為0,這樣做有什么意義?試着現在思考下題目中的問題(標紅色的部分),那么可想最糟糕的情況無非就是所有操作都是Push(s),代價為2n,並不像聚合代價那樣需要考慮其他兩個操作(攤還代價為0),時間復雜度為O(n)

 

 勢能法

 勢能法其實核算法有點相似,也有預付差額的,但不叫信用,而叫勢能,勢能法是從整體上看的,不像核算法那樣具體到某個操作,而是整體的勢能。

勢能法定義了一條公式;

                     Ci(攤還)=Ci(實際)+f(Di)-f(Di-1)          1

累加可得總攤還代價的公式為;

                     Ci(總攤還)= Ci(總實際)+ f(Di)-f(D0)        2

其中Ci 為每步操作的代價,f(Di)表示執行了第i個操作后的勢能,那個這個公式就可以理解為 i步操作的攤還代價等於第i步操作的實際代價加上從第i-1步操作到第i步操作的勢能變化,理解這個后,再來看棧操作的例子。

同樣Push(s)pop(s)的代價為1, mutlipop(s,k)的代價為k,我們規定入棧一個元素勢能加1,彈出一個元素勢能減1,那么f(Di)永遠為非負,f(D0)等於0,再根據上面的公式(2)即可知道這個又這里就可以確定總攤還代價是總實際代價的上界,所以現在要求的就是總攤還代價。

根據公式(1)可以得到Push(s)的攤還代價為2pop(s)的攤還代價為0mutlipop(s,k)的攤還代價也為0 (因為彈棧勢能要減,剛好和代價抵消,也可以看做勢能都用來支付代價了,所以下降了),那么又回到了核算法了,可得時間復雜度為O(n)

書上還有個例子是關於表擴張的,雖然能看懂,但還是理解的不太透徹(不明白他為什么能這么定義),在這里跟大家分享,也請大家指點~

例子:表擴張

是這樣的,有個程序,假設這個表只允許插入,當插入數據發現表滿了,會自動新建一個表大小為原來的兩倍,然后把已有的數據復制過去,再插入,在問題就是要求這個程序的代價,准確來說是攤還代價。

這里只寫兩個方法吧,寫多我自己都暈了..首先是聚合分析

我們將插入一條數據的代價看為1,假設一開始表的大小為1,沒有數據,可想除了表數據滿的情況,其他情況的代價都為1,而表滿時的大小都為2的冪。當表滿時插入數據的代價就是原有的數據復制的代價k(假設有k條數據)加上新插入的1,又此可得總攤還代價為

C(總攤還代價)<=n+20 +21+..+2lgn<n+2n=3n;(其中lgn表示表共擴張了lgn次,可以算出),所以攤還代價至多為3n/n=3

 下面看看核算法,通過核算法能很好的理解為什么攤還付代價為3.

書上是這樣分析的,假設現在表中有m/2條數據,表大小為m,而且沒有信用,那么插一條數據要付出3的代價,為什么?看,1是為了插入時消耗了,1是保存起來作為自己的信用,還有1呢,就是捐贈跟原本就在表中但沒有信用的數據,這樣,但數據插入了m/2條,一共有m條數據時,這也剛好是表要擴張的時候,表中所有的數據都有1的信用,就可以用來支付擴展表時復制到新表的代價,從而表的大小變成2m,數據剛好又沒了信用而且剛好是表大小的一半,這又到回了最初,就好像遞歸一樣,也就是說1條數據支持3代價就可以保證它永遠的擴展

 感嘆算法的思想博大精深,想研究透並不容易也談不上研究,只是偶爾讀讀會讓人心曠心怡,大家有想法一定要評論啊….

   

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM