在攤還分析中,通過求數據結構的一系列的操作的平均時間,來評價操作的代價。這樣,即使這些操作中的某個單一操作的代價很高,也可以證明平均代價很低。攤還分析不涉及概率,它可以保證最壞情況下每個操作的平均性能。
攤還分析有三種常用的技術:
聚合分析,它確定$n$個操作的總代價的上界為$T(n)$,所以每個操作的平均代價為$\frac{{T(n)}}{n}$。每個操作都有相同的攤還代價。
核算法:分析每個操作的攤還代價,不同於聚合分析,每種操作的攤還代價是不同的,核算法將序列中較早的操作的余額作為“信用”儲存起來,與數據結構中的特定對象相關聯,在隨后的操作中,儲存的信用可以用來進行支付。
勢能法:與核算法類似,也是分析每個操作的代價,但將勢能作為一個整體存儲,而與數據結構中的某個對象無關。
一、聚合分析
以棧操作為例:
存在3種操作:1、$push$ 2、$pop$ 3、$multipop$
直觀地分析復雜度:因為棧的大小最大為$n$,所以$multipop$的最壞情況為$O(n)$,所以,由n個$push$,$pop$,$multipop$組成的操作序列的最壞代價為$O( n^2)$,因為序列可能包含$O(n)$個操作序列。
上面的分析給出的界並不是緊確界,實際上,在一個空棧上執行$n$個$push$, $pop$, $multipop$的操作序列,代價最多為$O(n)$。這是因為,當一個對象壓入棧后,至多將其彈出一次。所以,對於一個非空的棧,可以執行的$pop$的次數(包含$multipop$中的$pop$)最多與$push$操作次數一樣,即$n$次。所以,對任意的$n$,任意一個由$n$個$push$ , $pop$,$multipop$組成的操作序列,最多花費$O(n)$。所以,每個操作的攤還代價為$O(1)$。
二、核函數
核算法,對不同的操作賦予不同的費用,這個費用就是攤還代價。當一個操作的攤還代價超過實際代價的時候,將差額存入數據結構中的特定對象,存入的差額稱為信用。對於后續操作中,攤還代價小於實際代價的情況,信用可以用來支付差額。
因為希望通過分析攤還代價來說明每個操作的平均代價的很小,所以應該確保$n$個操作序列的攤還代價是實際代價的上界。如果${c_i}$ 表示第i個操作的真實代價,而${c'_i}$表示攤還代價,則對於任意的$n$,有:$\sum\limits_{i = 1}^n {{c_i}^\prime } \ge \sum\limits_{i = 1}^n {{c_i}} $。因為信用就是攤還代價和實際代價的差值,即 $\sum\limits_{i = 1}^n {{c_i}^\prime } - \sum\limits_{i = 1}^n {{c_i}} $,所以需要保持數據結構中的總信用永遠為非負值。
依然以站操作為例:下面證明,如果按照攤還代價進行繳費,則可以支付任意的$n$個棧操作序列。在$push$操作時,共繳費2美元,其中1美元支付$push$的實際代價,將剩余的1美元存入插入的元素,作為信用。這樣,每個插入的元素都具有1美元的信用。這1美元的信用,實際上是用來支付$pop$操作的預付費。當執行一個$pop$的時候,並不繳額外的費用,而是使用信用來支付實際代價。$multipop$也一樣。所以,對任意的n個PUSH, POP, MULTIPOP組成的序列,總攤還代價為實際代價的上界,總攤還代價為$O(n)$。
三、勢能法
勢能法與核算法類似,但是勢能法並不將預付代價表示為數據結構中特定對象的信用,而是表示為“勢能”。勢能是與整個數據結構相關聯,而不是某個特定的對象。將勢能釋放,就可以支付未來操作的代價。
勢能法如下:對一個初始數據結構 ${D_0}$執行$n$個操作。對於i = 1, 2,...,n, ${c_i}$表示第i個操作的實際代價, ${D_i}$表示在數據結構 ${D_{i - 1}}$上執行第i個操作得到的數據結構。勢函數$\varphi $將每個數據結構${D_i}$映射到一個實數 $\varphi ({D_i})$,這個值就是關聯到數據結構 的勢。所以,第i個操作的攤還代價為${c'_i} = {c_i} + \varphi ({D_i}) - \varphi ({D_{i - 1}})$。每個操作的攤還代價等於其實際代價加上此操作引起的勢能變化。
勢能法其實就是核函數的總體分析。
再拿kmp算法是失配回退時使用的攤還分析技術:
這個可以用勢能分析法來分析:
關於匹配指針的位置$cur$
操作A:匹配時,$cur + + $;
操作B:失配時,$cur = next[cur - 1]$; (根據不同實現有所出入)
這個 $next[cur - 1] < = cur - 1$ 是成立的。
根據勢能分析($cur \ge 0$ 恆成立),我們可以證明,操作A的執行次數一定比操作B要多,兩個操作都是$O(1)$。
而操作A的執行次數是很容易分析最壞上界是 $O(n)$
那么 $O(n) = T(A) \ge T(B)$
因此匹配時的時間復雜度$T(A + B) = O(n)$
其實上述操作類似於棧操作,直接類比進行復雜度分析即可。