遞歸的使用,斐波那契數列實現及優化


一 .基本含義:

  ​    遞歸是指函數/過程/子程序在運行過程序中直接或間接調用自身而產生的重入現象。即遞歸是一個過程:函數不斷引用自身,直到引用的對象已知。

 

二 .使用遞歸的四大法則 :

    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次,大大的減少了重復的計算,符合了遞歸調用的第四法則。

 


免責聲明!

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



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