日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

斐波那契数列算法分析

發布時間:2025/3/20 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 斐波那契数列算法分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://www.cnblogs.com/CCBB/archive/2009/04/25/1443441.html

背景:

假定你有一雄一雌一對剛出生的兔子,它們在長到一個月大小時開始交配,在第二月結束時,雌兔子產下另一對兔子,過了一個月后它們也開始繁殖,如此這般持續下去。每只雌兔在開始繁殖時每月都產下一對兔子,假定沒有兔子死亡,在一年后總共會有多少對兔子?

在一月底,最初的一對兔子交配,但是還只有1對兔子;在二月底,雌兔產下一對兔子,共有2對兔子;在三月底,最老的雌兔產下第二對兔子,共有3對兔子;在四月底,最老的雌兔產下第三對兔子,兩個月前生的雌兔產下一對兔子,共有5對兔子;……如此這般計算下去,兔子對數分別是:1, 1, 2, 3, 5, 8, 13, 21, 34, 55,89, 144, ...看出規律了嗎?從第3個數目開始,每個數目都是前面兩個數目之和。這就是著名的斐波那契(Fibonacci)數列。

?

有趣問題:

1,有一段樓梯有10級臺階,規定每一步只能跨一級或兩級,要登上第10級臺階有幾種不同的走法?

答:這就是一個斐波那契數列:登上第一級臺階有一種登法;登上兩級臺階,有兩種登法;登上三級臺階,有三種登法;登上四級臺階,有五種方法……所以,1,2,3,5,8,13……登上十級,有89種。

2,數列中相鄰兩項的前項比后項的極限是多少,就是問,當n趨于無窮大時,F(n)/F(n+1)的極限是多少?

答:這個可由它的通項公式直接得到,極限是(-1+√5)/2,這個就是所謂的黃金分割點,也是代表大自然的和諧的一個數字。

?

?

數學表示:

Fibonacci數列的數學表達式就是:

F(n) = F(n-1) + F(n-2)

F(1) = 1

F(2) = 1

?

遞歸程序1:

Fibonacci數列可以用很直觀的二叉遞歸程序來寫,用C++語言的描述如下:

long fib1(int n)

{

??????????if (n <= 2)

{

??????????return 1;

}

else

{

??????????return fib1(n-1) + fib1(n-2);

}

}

看上去程序的遞歸使用很恰當,可是在用VC2005的環境下測試n=37的時候用了大約3s,而n=45的時候基本下樓打完飯也看不到結果……顯然這種遞歸的效率太低了!!

遞歸效率分析:

例如,用下面一個測試函數:

long fib1(int n, int* arr)

{

?????????arr[n]++;

?????????if (n <= 2)

?????????{

??????????????return 1;

?????????}

?????????else

?????????{

??????????????return fib1(n-1, arr) + fib1(n-2, arr);

?????????}

}

這時,可以得到每個fib(i)被計算的次數:

fib(10) = 1?????fib(9) = 1??????fib(8) = 2??????fib(7) = 3

fib(6) = 5??????fib(5) = 8??????fib(4) = 13????fib(3) = 21

fib(2) = 34???fib(1) = 55????fib(0) = 34

可見,計算次數呈反向的Fibonacci數列,這顯然造成了大量重復計算。

我們令T(N)為函數fib(n)的運行時間,當N>=2的時候我們分析可知:

T(N) = T(N-1) + T(N-2) + 2

而fib(n) = fib(n-1) + fib(n-2),所以有T(N) >= fib(n),歸納法證明可得:

fib(N) < (5/3)^N

當N>4時,fib(N)>= (3/2)^N

標準寫法:

顯然這個O((3/2)^N)?是以指數增長的算法,基本上是最壞的情況。

其實,這違反了遞歸的一個規則:合成效益法則。

合成效益法則(Compound interest rule):在求解一個問題的同一實例的時候,切勿在不同的遞歸調用中做重復性的工作。

所以在上面的代碼中調用fib(N-1)的時候實際上同時計算了fib(N-2)。這種小的重復計算在遞歸過程中就會產生巨大的運行時間。

?

遞歸程序2:

用一叉遞歸程序就可以得到近似線性的效率,用C++語言的描述如下:

long fib(int n, long a, long b, int count)

{

?????if (count == n)

?????????return b;

?????return fib(n, b, a+b, ++count);

}

?

long fib2(int n)

{

?????return fib(n, 0, 1, 1);

}

這種方法雖然是遞歸了,但是并不直觀,而且效率上相比下面的迭代循環并沒有優勢。

?

迭代解法:

Fibonacci數列用迭代程序來寫也很容易,用C++語言的描述如下:

//也可以用數組將每次計算的f(n)存儲下來,用來下次計算用(空間換時間)

long fib3 (int n)

{

?????long x = 0, y = 1;

?????for (int j = 1; j < n; j++)

?????{

?????????y = x + y;

?????????x = y - x;

?????}

?????return y;

}

這時程序的效率顯然為O(N),N = 45的時候<1s就能得到結果。

?

矩陣乘法:

我們將數列寫成:

Fibonacci[0] = 0,Fibonacci[1] = 1

Fibonacci[n] = Fibonacci[n-1] + Fibonacci[n-2] (n >= 2)

可以將它寫成矩陣乘法形式:

將右邊連續的展開就得到:

下面就是要用O(log(n))的算法計算:

顯然用二分法來求,結合一些面向對象的概念,C++代碼如下:

class?Matrix

{

public:

???????long?matr[2][2];

?

???????Matrix(const?Matrix&rhs);

???????Matrix(long?a,?long?b,?long?c,?long?d);

???????Matrix&?operator=(const?Matrix&);

???????friend?Matrix?operator*(const?Matrix& lhs,?const?Matrix& rhs)

???????{

??????????????Matrix ret(0,0,0,0);

??????????????ret.matr[0][0] = lhs.matr[0][0]*rhs.matr[0][0] + lhs.matr[0][1]*rhs.matr[1][0];

??????????????ret.matr[0][1] = lhs.matr[0][0]*rhs.matr[0][1] + lhs.matr[0][1]*rhs.matr[1][1];

??????????????ret.matr[1][0] = lhs.matr[1][0]*rhs.matr[0][0] + lhs.matr[1][1]*rhs.matr[1][0];

??????????????ret.matr[1][1] = lhs.matr[1][0]*rhs.matr[0][1] + lhs.matr[1][1]*rhs.matr[1][1];

??????????????return?ret;

???????}

};

?

Matrix::Matrix(long?a,?long?b,?long?c,?long?d)

{

???????this->matr[0][0] = a;

???????this->matr[0][1] = b;

???????this->matr[1][0] = c;

???????this->matr[1][1] = d;

}

?

Matrix::Matrix(const?Matrix &rhs)

{

???????this->matr[0][0] = rhs.matr[0][0];

???????this->matr[0][1] = rhs.matr[0][1];

???????this->matr[1][0] = rhs.matr[1][0];

???????this->matr[1][1] = rhs.matr[1][1];

}

?

Matrix& Matrix::operator?=(const?Matrix &rhs)

{

???????this->matr[0][0] = rhs.matr[0][0];

???????this->matr[0][1] = rhs.matr[0][1];

???????this->matr[1][0] = rhs.matr[1][0];

???????this->matr[1][1] = rhs.matr[1][1];

???????return?*this;

}

?

Matrix power(const?Matrix& m,?int?n)

{

???????if?(n == 1)

??????????????return?m;

???????if?(n%2 == 0)

??????????????return?power(m*m, n/2);

???????else

??????????????return?power(m*m, n/2) * m;

}

?

long?fib4 (int?n)

{

???????Matrix matrix0(1, 1, 1, 0);

???????matrix0 = power(matrix0, n-1);

???????return?matrix0.matr[0][0];

}

這時程序的效率為O(log(N))?。

?

公式解法:

在O(1)的時間就能求得到F(n)了:

?

注意:其中[x]表示取距離x最近的整數。

用C++寫的代碼如下:

long fib5(int n)

{

?????double z = sqrt(5.0);

?????double x = (1 + z)/2;

?????double y = (1 - z)/2;

?????return (pow(x, n) - pow(y, n))/z + 0.5;

}

這個與數學庫實現開方和乘方本身效率有關的,我想應該還是在O(log(n))的效率。

?

總結:

上面給出了5中求解斐波那契數列的方法,用測試程序主函數如下:

int main()

{

?????cout << fib1(45) << endl;

?????cout << fib2(45) << endl;

?????cout << fib3(45) << endl;

?????cout << fib4(45) << endl;

cout << fib5(45) << endl;

?????return 0;

}

函數fib1會等待好久,其它的都能很快得出結果,并且相同為:1134903170。

而后面兩種只有在n = 1000000000的時候會顯示出優勢。由于我的程序都沒有涉及到高精度,所以要是求大數據的話,可以通過取模來獲得結果的后4位來測試效率與正確性。

另外斐波那契數列在實際工作中應該用的很少,尤其是當數據n很大的時候(例如:1000000000),所以綜合考慮基本普通的非遞歸O(n)方法就很好了,沒有必要用矩陣乘法。

?

附錄:

程序全部源碼:

#include?<iostream>

#include?<vector>

#include?<string>

#include?<cmath>

#include?<fstream>

?

using?namespace?std;

?

class?Matrix

{

public:

???????long?matr[2][2];

?

???????Matrix(const?Matrix&rhs);

???????Matrix(long?a,?long?b,?long?c,?long?d);

???????Matrix&?operator=(const?Matrix&);

???????friend?Matrix?operator*(const?Matrix& lhs,?const?Matrix& rhs)

???????{

??????????????Matrix ret(0,0,0,0);

??????????????ret.matr[0][0] = lhs.matr[0][0]*rhs.matr[0][0] + lhs.matr[0][1]*rhs.matr[1][0];

??????????????ret.matr[0][1] = lhs.matr[0][0]*rhs.matr[0][1] + lhs.matr[0][1]*rhs.matr[1][1];

??????????????ret.matr[1][0] = lhs.matr[1][0]*rhs.matr[0][0] + lhs.matr[1][1]*rhs.matr[1][0];

??????????????ret.matr[1][1] = lhs.matr[1][0]*rhs.matr[0][1] + lhs.matr[1][1]*rhs.matr[1][1];

??????????????return?ret;

???????}

};

?

Matrix::Matrix(long?a,?long?b,?long?c,?long?d)

{

???????this->matr[0][0] = a;

???????this->matr[0][1] = b;

???????this->matr[1][0] = c;

???????this->matr[1][1] = d;

}

?

Matrix::Matrix(const?Matrix &rhs)

{

???????this->matr[0][0] = rhs.matr[0][0];

???????this->matr[0][1] = rhs.matr[0][1];

???????this->matr[1][0] = rhs.matr[1][0];

???????this->matr[1][1] = rhs.matr[1][1];

}

?

Matrix& Matrix::operator?=(const?Matrix &rhs)

{

???????this->matr[0][0] = rhs.matr[0][0];

???????this->matr[0][1] = rhs.matr[0][1];

???????this->matr[1][0] = rhs.matr[1][0];

???????this->matr[1][1] = rhs.matr[1][1];

???????return?*this;

}

?

Matrix power(const?Matrix& m,?int?n)

{

???????if?(n == 1)

??????????????return?m;

???????if?(n%2 == 0)

??????????????return?power(m*m, n/2);

???????else

??????????????return?power(m*m, n/2) * m;

}

?

//普通遞歸

long?fib1(int?n)

{

??????????????if?(n <= 2)

??????????????{

?????????????????????return?1;

??????????????}

??????????????else

??????????????{

?????????????????????return?fib1(n-1) + fib1(n-2);

??????????????}

}

/*上面的效率分析代碼

long fib1(int n, int* arr)

{

??????????????arr[n]++;

??????????????if (n <= 1)

??????????????{

?????????????????????return 1;

??????????????}

??????????????else

??????????????{

?????????????????????return fib1(n-1, arr) + fib1(n-2, arr);

??????????????}

}

*/

?

long?fib(int?n,?long?a,?long?b,?int?count)

{

???????if?(count == n)

??????????????return?b;

???????return?fib(n, b, a+b, ++count);

}

//一叉遞歸

long?fib2(int?n)

{

???????return?fib(n, 0, 1, 1);

}

?

//非遞歸方法O(n)

long?fib3 (int?n)

{

???????long?x = 0, y = 1;

???????for?(int?j = 1; j < n; j++)

???????{

??????????????y = x + y;

??????????????x = y - x;

???????}

???????return?y;

}

?

//矩陣乘法O(log(n))

long?fib4 (int?n)

{

???????Matrix matrix0(1, 1, 1, 0);

???????matrix0 = power(matrix0, n-1);

???????return?matrix0.matr[0][0];

}

?

//公式法O(1)

long?fib5(int?n)

{

???????double?z = sqrt(5.0);

???????double?x = (1 + z)/2;

???????double?y = (1 - z)/2;

???????return?(pow(x, n) - pow(y, n))/z + 0.5;

}

?

int?main()

{

???????//n = 45時候fib1()很慢

???????int?n = 10;

???????cout << fib1(n) << endl;

???????cout << fib2(n) << endl;

???????cout << fib3(n) << endl;

???????cout << fib4(n) << endl;

???????cout << fib5(n) << endl;

???????return?0;

}

轉載于:https://www.cnblogs.com/xiaomaohai/archive/2012/01/10/6157873.html

與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的斐波那契数列算法分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产亚洲欧美在线精品 | 久久精品视频8 | 久久精品福利 | 在线观看xxxx | 7777在线视频 | 灌篮高手全国大赛电影 | 色噜噜狠狠一区二区三区牛牛影视 | 国产午夜精品久久久久 | 色呦呦一区二区 | 国产精品国产三级国产三级人妇 | 凹凸精品一区二区三区 | 欧美做爰全过程免费看 | 久久91视频| 91gao | 色播视频在线播放 | 捆绑调教视频网站 | 亚洲成年人在线观看 | 日韩av线观看 | 日美女网站 | 农村老熟妇乱子伦视频 | 91美女在线视频 | 欧美性受xxxx黑人猛交88 | 日韩伦乱 | 欧美aⅴ | 亚洲h动漫| 久久国产免费看 | 精品久久a | 日本色www| 欧美cccc极品丰满hd | 日本人妻伦在线中文字幕 | 国产精品久久久久久久久久免费看 | 一道本在线观看视频 | 亚洲av久久久噜噜噜熟女软件 | 国产精品综合久久 | 日b视频在线观看 | 人妻熟女一区二区三区 | 噜噜在线视频 | 国产天堂av | 美女啪啪免费视频 | 国产xxxx | 99成人在线观看 | 欧美日韩精品一区二区在线观看 | 天天操夜夜操夜夜操 | 色婷婷av一区二区三区gif | 1000部拍拍拍18勿入免费视频 | 91福利视频导航 | 国产在线色 | 亚洲狠 | av丝袜天堂| 免费在线观看av片 | 亚洲国产精品999 | 最新国产视频 | 美女国产网站 | 懂色av蜜臂av粉嫩av | 欧美一级视频免费观看 | 中文字幕免费在线看线人动作大片 | a一级视频 | 激情欧美日韩 | 国内一区二区 | 国产又粗又黄又爽视频 | 色婷婷小说 | 亚洲第一色站 | 婷婷久 | 国产精品自慰网站 | 6090伦理 | 日韩一区二区久久 | 国产专区视频 | aaa一区二区 | 成人交性视频免费看 | 亚洲人 女学生 打屁股 得到 | 都市激情国产精品 | 成人高潮片免费 | 国语av在线| 久久精品欧美一区二区三区不卡 | 白又丰满大屁股bbbbb | 日本黄色不卡 | 一区二区高清 | 97在线免费 | 亚洲熟妇av一区二区三区 | 国产黄色三级 | 琪琪伦伦影院理论片 | 麻豆网站视频 | 麻豆国产精品一区 | 成人小视频在线 | 不卡的av在线播放 | 看国产毛片 | 美女网站视频在线观看 | 国产成人在线视频观看 | 天码人妻一区二区三区在线看 | 男人操女人免费网站 | 黑人巨大xxxxx性猛交 | 深夜福利一区二区三区 | 婷婷亚洲五月色综合 | 国产传媒视频在线观看 | 午夜国产片 | 国产亚洲精品美女 | 动漫涩涩免费网站在线看 | 色综合天天综合网国产成人网 | 国产成人亚洲精品自产在线 |