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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[CS101] 转载:浅议Fibonacci(斐波纳契)数列求解

發(fā)布時(shí)間:2024/9/20 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [CS101] 转载:浅议Fibonacci(斐波纳契)数列求解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原文轉(zhuǎn)載自林健隨筆的“淺議Fibonacci(斐波納契)數(shù)列求解”

Fibonacci 數(shù)列

描述了動物繁殖數(shù)量、植物花序變化等自然規(guī)律。作為一個(gè)經(jīng)典的數(shù)學(xué)問題,Fibonacci數(shù)列常作為例子出現(xiàn)在程序設(shè)計(jì)、數(shù)據(jù)結(jié)構(gòu)與算法等多個(gè)相關(guān)學(xué)科中。

下面簡單地分析一下常見的Fibonacci數(shù)列求解算法。

遞歸法

大多數(shù)教材在講解遞歸算法時(shí)總喜歡以Fibonacci數(shù)列為例,這是因?yàn)槲覀兛梢灾庇^地從定義公式的第三行看出Fibonacci數(shù)列的遞歸性。其C++實(shí)現(xiàn)如下:

unsigned long Fib(int n) {if (n <= 1) {return n;} else {return Fib(n - 1) + Fib(n - 2);} }

遞歸算法與定義公式十分吻合,容易理解,但計(jì)算過程存在大量重復(fù)的運(yùn)算,時(shí)間復(fù)雜度達(dá)到了O(2^n),使用的內(nèi)存空間也隨著函數(shù)調(diào)用棧的增長而增長。這顯然不適于實(shí)用的程序。

表驅(qū)動的遞歸法

(編者注:動態(tài)規(guī)劃)
這里不提純粹的表驅(qū)動法,因?yàn)閷τ陧?xiàng)數(shù)未知的Fibonacci數(shù)列開啟大片的空間來換取時(shí)間未免不值得且不負(fù)責(zé)。我們只是為了消除遞歸法中大量重復(fù)的運(yùn)算,可以將已經(jīng)計(jì)算過的中間值存入一個(gè)表,已備后續(xù)使用:

#define MAX_LOG 20 static unsigned long Logs[MAX_LOG] = {0}; unsigned long Fib(int n) {if (n <= 1) {return n;} else if (n < MAX_LOG && Logs[n] != 0) {return Logs[n];} else {Logs[n] = Fib(n - 1) + Fib(n - 2);return Logs[n];} }

當(dāng)n小于保存的表長時(shí),由于每個(gè)中間值只計(jì)算一次,時(shí)間復(fù)雜度降為O(n)。但隨著n的增大,要想維持O(n)的時(shí)間復(fù)雜度,就必須擴(kuò)大保存的表長,這就造成了存儲空間的浪費(fèi)。

迭代法

(編者注:遞推)
求Fibonacci數(shù)列第n項(xiàng)時(shí)雖然要用到前面兩項(xiàng)的值,但它們僅作為臨時(shí)計(jì)算的中間值,不作為結(jié)果輸出,因此無保留的必要,完全可以轉(zhuǎn)化成迭代法求解:

unsigned long Fib(int n) {int i;unsigned long a = 0, b = 1, c;if (n <= 1) {return n;} else {for (i = 2; i <= n; i++) {c = a + b;a = b;b = c;}return c;} }

迭代法的時(shí)間復(fù)雜度為O(n),使用的內(nèi)存空間也不會動態(tài)上漲。個(gè)人認(rèn)為Fibonacci數(shù)列更適宜作為迭代法而非遞歸法的典例出現(xiàn)在教材上。

下面給出兩種數(shù)學(xué)性較強(qiáng)的算法。考慮到表達(dá)的簡潔性,用Matlab實(shí)現(xiàn)

轉(zhuǎn)移矩陣法

此方法通常見于線性代數(shù)中的Markov過程示例。Fibonacci數(shù)列第n項(xiàng)與第n-1項(xiàng)可以通過轉(zhuǎn)移矩陣的n-1次迭代求出:

function y = Fib(n)first = [1; 0];trans = [1 1; 1 0];last = trans ^ (n - 1) * first;y = last(1, 1); end

此算法的時(shí)間復(fù)雜度相當(dāng)于計(jì)算矩陣乘方的時(shí)間復(fù)雜度。在計(jì)算2階矩陣n次方時(shí),如果直接按矩陣乘法定義式展開,不加特別優(yōu)化,其時(shí)間復(fù)雜度為O(n)。

通項(xiàng)公式法

Fibonacci數(shù)列的通項(xiàng)公式如下(證明略):

function y = Fib(n)sr5 = sqrt(5);y = uint32((((1 + sr5) / 2) ^ n - ((1 - sr5) / 2) ^ n) / sr5); end

該方法的時(shí)間復(fù)雜度貌似為O(1),但我們還應(yīng)該考慮乘方運(yùn)算的時(shí)間消耗。不加特別優(yōu)化時(shí),用乘法實(shí)現(xiàn)n次乘方的時(shí)間復(fù)雜度為O(n)。考慮到浮點(diǎn)數(shù)計(jì)算效率和精度問題,此方法在計(jì)算機(jī)實(shí)現(xiàn)時(shí)不如轉(zhuǎn)移矩陣法。

下面再給出兩種對計(jì)算機(jī)實(shí)現(xiàn)有特別意義,但同時(shí)有一定局限性的實(shí)現(xiàn)方法(只是實(shí)現(xiàn)方法,不能稱為新的算法)。其中使用了一些C++編程技巧,對使用其它語言實(shí)現(xiàn)也有一定的參考價(jià)值:

模板元編程法

通常我們在C++中使用模板,僅限于類模板與函數(shù)模板。事實(shí)上C++支持模板元編程,理論上可以在編譯時(shí)執(zhí)行任何計(jì)算(甚至包含選擇、循環(huán)、遞歸等結(jié)構(gòu))。代碼如下:

#define Fib(N) FibT<N>::Val template<int n> struct FibT {enum{Val = FibT<n - 1>::Val + FibT<n - 2>::Val}; }; template<> struct FibT<0> {enum{Val = 0}; }; template<> struct FibT<1> {enum{Val = 1}; };

我們用一個(gè)結(jié)構(gòu)體作為模板的載體,用一個(gè)枚舉值保存運(yùn)算結(jié)果。其中第一個(gè)模板為基本遞歸過程(使用遞歸算法是為了說明的簡便,完全可以用其它算法替代,以加速編譯過程),后兩個(gè)模板為n=0、1時(shí)的模板特化。通過#define語句將模板調(diào)用簡寫成類似函數(shù)調(diào)用的方式。程序在編譯時(shí)運(yùn)算所需的 Fibonacci數(shù)列項(xiàng),將結(jié)果作為常量嵌入編譯好的程序。運(yùn)行時(shí)直接使用結(jié)果,時(shí)間復(fù)雜度真正地變成了O(1)。但這一方法最大的局限就是只能對常量嵌入,程序中出現(xiàn)諸如計(jì)算Fib(i++)的情況則無能為力。盡管如此,這比在代碼中手工計(jì)算并寫入所需的值要直觀準(zhǔn)確,比通過純粹的表驅(qū)動法“空間換時(shí)間”要方便快捷

函數(shù)對象法

此方法主要用于C++ STL編程的通用算法方面,其執(zhí)行行為也有別于以上其它方法:

class Fib { public:Fib() : a(0), b(1), n(0){}unsigned long operator()(){if (n <= 1) {n++;return n - 1;} else {int c;c = a + b;a = b;b = c;return c;}} private:int a, b, n; };

這個(gè)函數(shù)類對象的行為可以理解為一個(gè)“Fibonacci數(shù)列發(fā)生器”,其測試性調(diào)用如下,程序?qū)⒁来未蛴?/p> void test(int i) {Fib fib;do {cout << fib() << endl;} while (i--); }

函數(shù)對象具有與函數(shù)指針類似的行為,同時(shí)又能保存自身的一些屬性,因此常用于STL通用算法編程。但針對單個(gè)的Fibonacci數(shù)列項(xiàng)求值,靈活性不如一般的方法。
希望讀者能夠從上面的算法分析中舉一反三,有所領(lǐng)悟。

參考資料

  • Bruce Eckel,Thinking In C++ Volume 2: Practical Programming,機(jī)械工業(yè)出版社,2006

  • William J. Collins,Data Structures and the Standard Template Library,機(jī)械工業(yè)出版社,2003

  • Knott's Surrey University,The Home page for Fibonacci Numbers and the Golden Section,http://www.mcs.surrey.ac.uk/Personal/R.Knott/Fibonacci/

  • 總結(jié)

    以上是生活随笔為你收集整理的[CS101] 转载:浅议Fibonacci(斐波纳契)数列求解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。