1. 程式人生 > >資料結構::遞迴時間複雜度的計算

資料結構::遞迴時間複雜度的計算

開篇前言:為什麼寫這篇文章?筆者目前在學習各種各樣的演算法,在這個過程中,頻繁地碰到到遞迴思想和分治思想,驚訝於這兩種的思想的偉大與奇妙的同時,經常要面對的一個問題就是,對於一個給定的遞迴演算法或者用分治思想縮小問題規模的演算法,如何求解這個演算法的時間複雜度呢?在google過很多的博文後,感覺這些博文總結的方法,有很好優秀的地方,但是都不夠全面,有感於此,筆者決定總結各家之長,作此博文,總結各種方法於此,有不足之處,歡迎各位批評指證!

  在演算法的分析中,當一個演算法中包含遞迴呼叫時,其時間複雜度的分析會轉化成為一個遞迴方程的求解。而對遞迴方程的求解,方法多種多樣,不一而足。本文主要介紹目前主流的方法:代入法,迭代法,公式法,母函式法,差分方程法。

   【代入法】代入法首先要對這個問題的時間複雜度做出預測,然後將預測帶入原來的遞迴方程,如果沒有出現矛盾,則是可能的解,最後用數學歸納法證明。

  【舉   例】我們有如下的遞迴問題:T(n)=4T(n/2)+O(n),我們首先預測時間複雜度為O(n2),不妨設T(n)=kn2(其中k為常數),將該結果帶入方程中可得:左=kn2,右=4k(n/2)2+O(n)=kn2+O(n),由於n2的階高於n的階,因而左右兩邊是相等的,接下來用數學歸納法進行驗證即可。

   【迭代法】迭代法就是迭代的展開方程的右邊,直到沒有可以迭代的項為止,這時通過對右邊的和進行估算來估計方程的解。比較適用於分治問題的求解,為方便討論起見,給出其遞迴方程的一般形式:

  【舉   例】下面我們以一個簡單的例子來說明:T(n)=2T(n/2)+n2,迭代過程如下:

  容易知道,直到n/2^(i+1)=1時,遞迴過程結束,這時我們計算如下:

  到這裡我們知道該演算法的時間複雜度為O(n2),上面的計算中,我們可以直接使用無窮等比數列的公式,不用考慮項數i的約束,實際上這兩種方法計算的結果是完全等價的,有興趣的同學可以自行驗證。

  【公式法】這個方法針對形如:T(n) = aT(n/b) + f(n)的遞迴方程。這種遞迴方程是分治法的時間複雜性所滿足的遞迴關係,即一個規模為n的問題被分成規模均為n/b的a個子問題,遞迴地求解這a個子問題,然後通過對這a個子問題的解的綜合,得到原問題的解。這種方法是對於分治問題最好的解法,我們先給出如下的公式:

  公式記憶:我們實際上是比較n^logba和f(n)的階,如果他們不等,那麼T(n)取他們中的較大者,如果他們的階相等,那麼我們就將他們的任意一個乘以logn就可以了。按照這個公式,我們可以計算【迭代法】中提到的例子:O(f(n))=O(n2),容易計算另外一個的階是O(n),他們不等,所以取較大的階O(n2)。太簡單了,不是嗎?

  需要注意:上面的公式並不包含所有的情況,比如第一種和第二種情況之間並不包含下面這種情況:f(n)是小於前者,但是並不是多項式的小於前者。同樣後兩種的情況也並不包含所有的情況。為了好理解與運用的情況下,筆者將公式表述成如上的情況,但是並不是很嚴謹,關於該公式的嚴密討論,請看這裡。但是公式的不包含的情況,我們很少很少碰到,上面的公式適用範圍很廣泛的。

  特別地,對於我們經常碰到的,當f(n)=0時,我們有:

  【母函式法】母函式是用於對應於一個無窮序列的冪級數。這裡我們解決的遞迴問題是形如:T(n)=c1T(n-1)+c2T(n-2)+c3T(n-3)+...+ckT(n-k)+f(n)。為說明問題簡便起見,我們選擇斐波那契數列的時間複雜度作為例子進行討論。

  【舉  例】斐波那契數列遞迴公式:T(n)=T(n-1)+T(n-2)。這裡我們假設F(n)為第n項的運算量。則容易得到:F(n)=F(n-1)+F(n-2),其中F(1)=F(2)=1.我們構造如下的母函式:G(x)=F(1)x+F(2)x2+F(3)x3+......,我們可以推導如下:

  上面的方法計算相對來說是比較簡單的,關鍵在於對於母函式的理解,剛開始的時候可能不是很好理解,對於母函式可以參考這裡維基百科這裡

  【差分方程法】可以將某些遞迴方程看成差分方程,通過解差分方程的方法來解遞迴方程,然後對解作出漸近階估計。這裡我們只考慮最長常見的遞迴形式,形如:T(n)=c1T(n-1)+c2T(n-2)+c3T(n-3)+...+ckT(n-k)+f(n),其中c1,c2,...ck為常數且不等於0;我們對該方程的求解如下:

  對應上面的齊次方程的特徵方程為:

  如果解得t=r是該特徵方程的m重根,則這m個解的形式為:{rn     n*rn      n2rn   ...    nm-1rn},其餘的關於複數解的形式和普通的線性方程組的形式類似,不再贅述。接下來,我們要求解該方程的對應非齊次方程組的通解,這裡我們針對該方程的特殊形式,不加證明地給出如下的通解形式:

  則和線性代數中的解一樣,原方程的解等於齊次方程組的通解+特解,即:

  最後由初始條件確定a(i)的值即可。

  為了幫助理解,我們舉兩個例子看看,就明白是怎麼回事了。

  【舉 例1】遞迴方程如下:

(1)寫出對應齊次方程的特徵方程:

得到基礎解係為:{t1n,  t2n}

(2)計算特解,對於本題,直接觀察得特解為:-8

(3)得到原方程解的形式為:T(n)=a0t1n+a1t2n-8

(4)代入n=0,n=1的情況,得到a0,a1,最後可得:

  可以看到該方程形式和上面討論過的斐波那契數列只差一個常數8,因而兩者的時間複雜度是相同的。有興趣的同學可以按照這個方法再次計算斐波那契數列的時間複雜度驗證一下。

  【舉  例2】遞迴方程如下:

(1)計算對應齊次方程的基礎解析:

特徵方程為:C(t)=t^2-4t-4=0,得到一個2重根t=2.因而其基礎解為:{2n      n*2n}

(2)由於f(n)=n*2n,對應上面表格的最後一種情況,得到特解形式為:T(n)=n2(p0+p1n)2n代入原遞迴方程可得:p0=1/2,p1=1/6

(3)原方程解的形式為:T(n)=a0*2n+a1*n*2n+n2(1/2+n/6)2n,代入T(0),T(1)得:a0=a1=0

(4)綜上:T(n)=n2(1/2+n/6)2n

因而時間複雜度為:O(n32n)