一 .基本含義:
遞歸是指函數/過程/子程序在運行過程序中直接或間接調用自身而產生的重入現象。即遞歸是一個過程:函數不斷引用自身,直到引用的對象已知。
二 .使用遞歸的四大法則 :
1. 基准情形: 必須有某些基准情形,它無需遞歸即可解出。
2. 不斷推進: 對於需要遞歸求解的情形,每次遞歸調用都必須使得求解狀況朝着基准情形推進。
3. 設計法則: 假設所有的遞歸調用都能運行。
4. 合成效益法則:在求解一個問題的同一實例時,切勿在不同的遞歸調用中做重復性工作。
其中第四點在遞歸的效率中至為關鍵。這是為什么用遞歸實現斐波那契數列的常規方法時效率很低的原因,而在二叉樹中表現相當優良的原因!
三.關於斐波那契數列的遞歸實現及優化
斐波那契數列 又稱為“兔子數列”,指的是這樣一個數列:1、1、2、3、5、8、13、21、34、……在數學上,斐波納契數列以如下被以遞歸的方法定義:F(0)=0,F(1)=1, F(n)=F(n-1)+F(n-2),即從第三項開始每一項都等於前面兩項的和。
根據定義很容易用遞歸實現的方法,
public static long fib(long n){
n1++;//記錄被調用的次數
if(n<2){//基准情形,法則1
return n;
}
return fib(n-1)+fib(n-2); //通過調用自身,不斷推進直到達到基准情形,法則2,3
}
通過觀察上面的代碼,我們發現一個問題,當給定一個數N時,需要先計算N-1 和N-2的情況,但是在計算N-1時同樣要用計算N-2的情況,每個遞歸調用都觸發另外兩個遞歸調用,而這兩個調用的任何一個又將調用另外連個遞歸調用,這樣冗余計算的增量是非常快的,例如圖:

再計算 fib(5)時,需要先求fib(4)和fib(3),
而求fib(4)時又要求fib(3)和fib(2)以此類推這樣就做了大量重復計算造成了不必要的浪費,如果我們能把fib(3),fib(2),fib(1)計算好的數據先存起來,下次需要計算時直接調用就可以省去大量的重復計算,因而有了下面的優化方式:
public static long newFib(long a,long b ,long n){
n2++;//記錄被調用的次數
if(n>=2){
return newFib(a+b,a,n-1);//將本次計算的結果和上次計算的結果作為參數傳入下一次計算中,以減少重復計算。第四法則
}
return a;
}
測試:
static int n1;
static int n2;
public static void main(String[] args)
{
/* int n = 10;//第幾個斐波那契數列
int a = 1; //斐波那契數列的第一項
int b = 1;//第二項
long i = fib(n);//普通的遞歸
long j =newFib(a,b,n);//優化后的遞歸
System.out.println("第n個fibon數是--"+i);
System.out.println("次數--"+n1);
System.out.println("第n個fibon數是--"+j);
System.out.println("次數--"+n2);
}
輸出結果為:
根據結果可以看出,當n=10時,未經優化的方法被調用了177次,而優化后的方法僅僅被調用了9次,大大的減少了重復的計算,符合了遞歸調用的第四法則。
