1. 程式人生 > >Fibonacci數列遞迴演算法與非遞迴演算法

Fibonacci數列遞迴演算法與非遞迴演算法

轉載於:http://blog.csdn.net/qq_33951180/article/details/52484080

一、斐波那契數列 
由於斐波納挈數列是以兔子的繁殖引入的,因此也叫“兔子數列”。它指的是這樣一個數列:0,1,1,2,3,5,8,13……從這組數可以很明顯看出這樣一個規律:從第三個數開始,後邊一個數一定是在其之前兩個數的和。在數學上,斐波納挈數列可以以這樣的公式表示: 
F(0) = 0 
F(1) = 1 F(n) = F(n-1) + F(n-2),(n>=2)

二、斐波那契數列的實現 
既然該數列已經有這樣一個規律:F(n) = F(n-1) + F(n-2);那麼我們很容易就能想到用遞迴的方法,這樣寫出來的程式碼比較簡潔

int fibo1(int n)
{
    assert(n >= 0);
    if(n == 1 || n == 0) return n;
    return fibo1(n - 1) + fibo1(n - 2);
}

當然,我們也可以這樣寫:

int fibo1(int n)
{
    assert(n >= 0);
    return n < 2 ? n : fibo1(n - 1) + fibo1(n - 2);
}

 

這樣的遞迴演算法雖然只有簡單的幾行,但是效率卻很低。為什麼呢?我們可以分析其遞迴呼叫的時間複雜度: 
時間複雜度 —– O(2^N)

 
由於使用遞迴時,其執行步驟是:要得到後一個數之前必須先計算出之前的兩個數,即在每個遞迴呼叫時都會觸發另外兩個遞迴呼叫,例如:要得到F(10)之前得先得到F(9)、F(8),那麼得到F(9)之前得先得到F(8)、F(7)……如此遞迴下去 
圖解 
從上圖我們可以看出,這樣的計算是以 2 的次方在增長的。除此之外,我們也可以看到,F(8)和F(7)的值都被多次計算,如果遞迴的深度越深,那麼F(8)和F(7)的值會被計算更多次,但是這樣計算的結果都是一樣的,除了其中之一外,其餘的都是浪費,可想而知,這樣的開銷是非常恐怖的!

所以,如果在時間複雜度和空間複雜度都有要求的話,我們可以用以下兩種非遞迴演算法來實現: 
@@:時間複雜度為O(N),空間複雜度為O(N)

 
建立一個數組,每次將前兩個數相加後直接賦給後一個數。這樣的話,有N個數就建立一個包含N個數的一維陣列,所以空間複雜度為O(N);由於只需從頭向尾遍歷一邊,時間複雜度為O(N)

int* fibo2(int n)
{
    assert(n >= 0);
    int* pArr = new int[n + 1];
    pArr[0] = 0;
    pArr[1] = 1;
    for(int i = 2; i <= n; i++){
        pArr[i] = pArr[i - 1] + pArr[i - 2]; 
    }
    return pArr;
}

 

@@:時間複雜度為O(N),空間複雜度為O(1) 
藉助兩個變數 nFirst 和 nSecond ,每次將 nFirst 和 nSecond 相加後賦給 nThird,再將 nSecond 賦給 nFirst ,nThird賦給 nSecond ,如此迴圈。

int fibo3(int n)
{
    assert(n >= 0);
    int nFirst = 0;
    int nSecond = 1;
    int nThird = 0;
    for(int i = 2 ; i <= n; i++){
        nThird = nFirst + nSecond;
        nFirst = nSecond;
        nSecond = nThird;
    }
    return nThird;
}

測試

int main()
{
    int n;
    cout << "請輸入數列項:";
    cin >> n;
    cout << "斐波那契數列前" << n << "項如下" << endl;
    for(int i = 0; i < n; i++){
        cout << fibo1(i) << "\t";
    }
    cout << endl;
    int* pArr = fibo2(n);
    for(int i = 0; i < n; i++){
        cout << pArr[i] << "\t";
    }
    delete[] pArr; pArr = NULL;
    cout << endl;
    for(int i = 0; i < n; i++){
        cout << fibo3(i) << "\t";
    }
    cout << endl;

    system("pause");

    return 0;
}

fibo