斐波那契數列的遞歸,迭代(循環),通項公式三種實現

謂Fibonacci數列是指這樣一種數列,它的前兩項均爲1,從第三項開始各項均爲前兩項之和。用數學公式表示出來就是:

           1                            (n=1,2)
fib(n)=
           fib(n-1)+fib(n-2)     (n>2)
可以證明斐波那契數列的通項公式爲fib(n) = [(1+√5)/2]^n /√5 - [(1-√5)/2]^n /√5 (n=1,2,3.....),關於斐波那契數列的詳細介紹請參閱百度百科
下面我將介紹三種比較常用的求解第n項斐波那契數列的方法:遞歸法、迭代法、通項公式法。
1、遞歸法
這種方法的優點是簡潔和容易理解,缺點是時間複雜度太大,隨着n的增大,運算時間將會急劇增加。因此在很多場合這種方法是不可取的。
使用這種方法的關鍵代碼是:
if(n == 1|| n== 2)
{
    return 1;
}
else
{
    return fib(n - 1) + fib(n - 2);
}
2、迭代法
這種方法相對於遞歸法來說在時間複雜度上減小了不少,但代碼相對就要複雜些了。它的思想是這樣的,假設開始時f0=1,f1=1,currentFib表示當前斐波那契數,則:
for(i = 1;i < n;i++)
{
    currentFib = f0 + f1;
    f0 = f1;
    f1 = currentFib;
}
這樣迭代結束和currentFib就是fib(n)了。
3、通項公式法
這種方法是最沒技術含量的方法,只要你知道通項公式照着把它翻譯成編程語言就可以了,優點不言而喻。
fib(n) = pow(((1 + sqrt(5)) / 2.0),n) / sqrt(5) - pow(((1 - sqrt(5)) / 2.0),n) / sqrt(5));
小結:
這三種方法各有優缺點,使用哪種方法根據實際情況確定,從時間複雜度上來說O(通向公式法)<O(迭代法)<O(遞歸法)。
下面我做了一個簡單的測試:分別測試這三種方法計算0-30這31個斐波那契數所用的總時間。從測試結果看,遞歸確實很費時,特別是n在30以後計算起來就很費時了,而另外兩種方法計算這31個斐波那契數所費時間基本爲0。當然結果不會很準確,但至少能說明問題。
測試代碼:
************************************************************************************************************************************
#include <stdio.h>
#include <math.h>
#include <time.h>
#define ROOT_OF_FIVE sqrt(5.0)
long double fib1(int n);
//使用遞歸
long double fib2(int n);
//使用迭代
long double fib3(int n);
//使用通項公式
int main()
{
    int i;
    long double result1[31],result2[31],result3[31],consume[3],start,finish;
    printf("N           遞歸法          迭代法          通項公式法/n");
    
    start = (long double)clock();
    for(i = 0;i <= 30;i++)
    {    
        result1[i] = fib1(i);
    }
    finish = (long double)clock();
    consume[0] = finish - start;

    start = (long double)clock();
    for(i = 0;i <= 30;i++)
    {    
        result2[i] = fib2(i);
    }
    finish = (long double)clock();
    consume[1] = finish - start;

    start = (long double)clock();
    for(i = 0;i <= 30;i++)
    {    
        result3[i] = fib3(i);
    }
    finish = (long double)clock();
    consume[2] = finish - start;

    for(i = 0;i <= 30;i++)
    {
        printf("%02d          %06.0lf          %06.0lf          %06.0lf/n",i,result1[i],result2[i],result3[i]);
    }
    printf("Total time: %lfms    %lfms      %lfms/n",consume[0],consume[1],consume[2]);
    return 0;
}
===============================================================================================================
long double fib1(int n)
{//使用遞歸
    if(n == 0)
    {
        return 0;
    }
    else if(n == 1)
    {
        return 1;
    }
    else
    {
        return fib1(n - 1) + fib1(n - 2);
    }
}

long double fib2(int n)
{//使用迭代
    if(n == 0)
    {
        return 0;
    }
    else if(n == 1)
    {
        return 1;
    }
    else
    {
        long double f0 = 0,f1 = 1,currentFib;
        int i;
        for(i = 1;i < n;i++)
        {
            currentFib = f0 + f1;
            f0 = f1;
            f1 = currentFib;
        }
        return currentFib;
    }
}

long double fib3(int n)
{//使用通項公式Fib(n) = [(1+√5)/2]^n /√5 - [(1-√5)/2]^n /√5
    return (pow(((1 + ROOT_OF_FIVE) / 2.0),n) / ROOT_OF_FIVE - 
        pow(((1 - ROOT_OF_FIVE) / 2.0),n) / ROOT_OF_FIVE);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章