C语言用递归求斐波那契数,让你发现递归的缺陷和效率瓶颈
生活随笔
收集整理的這篇文章主要介紹了
C语言用递归求斐波那契数,让你发现递归的缺陷和效率瓶颈
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
C語言用遞歸求斐波那契數(shù),讓你發(fā)現(xiàn)遞歸的缺陷和效率瓶頸
分享到:一般需要遞歸解決的問題有兩個(gè)特點(diǎn):
- 存在限制條件,當(dāng)符合這個(gè)條件時(shí)遞歸便不再繼續(xù);
- 每次遞歸調(diào)用之后越來越接近這個(gè)限制條件。
遞歸使用最常見的一個(gè)例子就是求階乘,具體描述和代碼請(qǐng)看這里:C語言遞歸和迭代法求階乘
但是,遞歸函數(shù)調(diào)用將涉及一些運(yùn)行時(shí)開銷——參數(shù)必須壓到堆棧中,為局部變量分配內(nèi)存空間(所有遞歸均如此,并非特指求階乘這個(gè)例子),寄存器的值必須保存等。當(dāng)遞歸函數(shù)的每次調(diào)用返回時(shí),上述這些操作必須還原,恢復(fù)成原來的樣子。所以, 基于這些開銷,對(duì)于遞歸求階乘而言,它并沒有簡(jiǎn)化問題的解決方案。
迭代求階乘使用簡(jiǎn)單循環(huán)的程序,看上去不甚符合前面階乘的數(shù)學(xué)定義,但它卻能更為有效地計(jì)算出結(jié)果。如果你仔細(xì)觀察遞歸函數(shù),你會(huì)發(fā)現(xiàn)遞歸調(diào)用是函數(shù)所執(zhí)行的最后一項(xiàng)任務(wù)。這個(gè)函數(shù)是尾部遞歸(tail recursion)的一個(gè)例子。由于函數(shù)在遞歸調(diào)用返回之后不再執(zhí)行任何任務(wù),所以尾部遞歸可以很方便地轉(zhuǎn)換成一個(gè)簡(jiǎn)單循環(huán),完成相同的任務(wù)。
提示:許多問題是以遞歸的形式進(jìn)行解釋的,這只是因?yàn)樗确沁f歸形式更為清晰。但是,這些問題的迭代實(shí)現(xiàn)往往比遞歸實(shí)現(xiàn)效率更高,雖然代碼的可讀性可能稍差一些,當(dāng)一個(gè)問題相當(dāng)復(fù)雜,難以用迭代形式實(shí)現(xiàn)時(shí),此時(shí)遞歸實(shí)現(xiàn)的簡(jiǎn)潔性便可以補(bǔ)償它所帶來的運(yùn)行時(shí)開銷。
這里有一個(gè)更為極端的例子,菲波那契數(shù)就是一個(gè)數(shù)列,數(shù)列中每個(gè)數(shù)的值就是它前面兩個(gè)數(shù)的和。 這種關(guān)系常常用遞歸的形式進(jìn)行描述:
同樣,這種遞歸形式的定義容易誘導(dǎo)人們使用遞歸形式來解決問題。這里有一個(gè)陷牌:它使用遞歸步驟計(jì)算Fibonacci(n-1)和Fibonacci(n-2)。但是,在計(jì)算Fibonacci(n-1)時(shí)也將計(jì)算Fibonacci(n-2)。這個(gè)額外的計(jì)算代價(jià)有多大呢?
答案是,它的代價(jià)遠(yuǎn)遠(yuǎn)不止一個(gè)冗余計(jì)算:每個(gè)遞歸調(diào)用都觸發(fā)另外兩個(gè)遞歸調(diào)用,而這兩個(gè)調(diào)用的任何一個(gè)還將觸發(fā)兩個(gè)遞歸調(diào)用,再接下去的調(diào)用也是如此。這樣,冗余計(jì)算的數(shù)量增長得非常快。例如,在遞歸計(jì)算Fibonacci(10)時(shí),Fibonacci(3)的值被計(jì)算了21次。但是,在遞歸計(jì)算 Fibonacci(30)時(shí),Fibonacci(3)的值被計(jì)算了317811次。當(dāng)然,這317811次計(jì)算所產(chǎn)生的結(jié)果是完全一樣的,除了其中之一外,其余的純屬浪費(fèi)。這個(gè)額外的開銷真是相當(dāng)恐怖!
如果使用一個(gè)簡(jiǎn)單循環(huán)來代替遞歸,這個(gè)循環(huán)的形式肯定不如遞歸形式符合前面菲波那契數(shù)的抽象定義,但它的效率提高了幾十萬倍!
當(dāng)你使用遞歸方式實(shí)現(xiàn)一個(gè)函數(shù)之前,先問問你自己使用遞歸帶來的好處是否抵得上它的代價(jià)。 而且你必須小心:這個(gè)代價(jià)可能比初看上去要大得多。
不信請(qǐng)看下面的代碼,分別用遞歸和迭代計(jì)算斐波那契數(shù),效率差距真是大的驚人。 復(fù)制純文本復(fù)制
注意:上面的程序最好在GCC(Linux下的GCC或Windows下的Code:Blocks)下運(yùn)行,VC下可能統(tǒng)計(jì)不到運(yùn)行時(shí)間。
看吧,用遞歸花了將近7.5秒的時(shí)間,但是用迭代幾乎不費(fèi)吹灰之力,效率快到統(tǒng)計(jì)不到運(yùn)行時(shí)間。 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)
總結(jié)
以上是生活随笔為你收集整理的C语言用递归求斐波那契数,让你发现递归的缺陷和效率瓶颈的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NAT虚拟网络配置
- 下一篇: Mr. Bender and Squar