我以前一直誤解了遞歸的意義,併爲自己能在程序中多寫幾個遞歸高興。現在我發現錯了!遞歸顯然能讓程序看起來非常簡潔,但是,由於會引起函數的多次調用,將大大的降低程序的效率。那我們討論遞歸幹什麼?基於以下這兩個願因:
第一,也是最重要的原因,遞歸告訴了我們一種思考問題的方法。因爲,確實是有一些問題,如果不用遞歸的思想去思考,我們將束手無策!最明顯的例子就是漢諾塔的問題。
但是,正如前面提到的,遞歸的效率並不高。因此,我可以利用遞歸去思考,但如果做得到的話,儘可能用循環或直接計算去替代遞歸,如何把遞歸轉換爲循環或直接計算,將在閉合形式解中討論。
第二,就像不能根除goto語句一樣,遞歸在某些時候確實沒有替代品。所以,學會熟練的寫出遞歸程序,仍是必備的能力。這裏簡要的說一說如何寫遞歸的程序。
最簡單的遞歸由兩部分組成:1、初始情況(base case)。2、遞歸部分(recursive call)
就拿漢諾塔的問題吧(摘自Clifford A. Shaffer 的數據結構與算法 第二版):
void TOH(int n,Pole start,Pole temp)
{
if(n == 0) return; //base case
//把n-1塊從start移到temp
TOH(n-1,start,temp,goal); //recursive call
//把start最上面那一塊移到goal
mov(start,goal); //move one disk
//把n-1塊從temp移到goal
TOH(n-1,temp,goal,start); //recursive call
}
二、閉合形式解(closed form solution)
閉合形式解:一個能直接計算級數和或遞歸結果的等式。
其實,這應該屬於高中的知識了。例如,已經一個遞歸:T(n) = T(n-1)+ n^2;
那麼根據高中的數學知識,可以解出:
T(n) = n^2 + (n-1)^2 + (n-2)^2 + ... + 2^2 + 1^2
= (2*n^3 + 3n^2 + n)/6
這樣就可以用直接計算的方法來代替遞歸了。效率顯著提高