C語言深入探索遞歸的特點(diǎn)
遞歸的認(rèn)識(shí)
基本認(rèn)識(shí):
1.首先遞歸的本質(zhì)還是函數(shù)調(diào)用,也要形成和釋放棧幀。
2.函數(shù)的調(diào)用是有成本的,這個(gè)成本在時(shí)間和空間上表現(xiàn)為函數(shù)棧幀的形成和銷毀。
3.遞歸就是 不斷形成棧幀和銷毀的過程。
理論認(rèn)識(shí):
1.內(nèi)存和cpu中的資源有限,也就決定啦,合理的遞歸是絕對(duì)不可以無限遞歸下去的。
2.遞歸不是什么時(shí)候都可以使用的,而是要滿足自身的場(chǎng)景,即目標(biāo)函數(shù)的子問題可以用該算法解決,本質(zhì)是分治的思想。
3.遞歸的核心:大事化小,遞歸出口。
main函數(shù)可以遞歸嗎
相信有些讀者就在疑惑啦?main函數(shù)是主函數(shù)呀,這個(gè)怎么可以自己調(diào)用自己呢?
實(shí)際上,main函數(shù)本質(zhì)也是函數(shù),所以也就會(huì)形成棧幀,所以是可以自己調(diào)用自己的。
代碼和運(yùn)行結(jié)果如下:
int main() { printf("胡楊樹下\n"); Sleep(100);//睡眠0.1秒 main(); return 0; }
結(jié)果顯示是可以調(diào)用的,那么我們也能過看出來,這個(gè)main函數(shù)的遞歸是不會(huì)自動(dòng)停止的,停止時(shí)就是發(fā)生棧溢出,那么函數(shù)的棧幀是怎么形成的呢?
是最下面的main函數(shù)進(jìn)行調(diào)用自身形成棧幀,如圖示,我們可以看出,這些函數(shù)調(diào)用都開辟了空間,所以要占用內(nèi)存,而且形成棧幀后需要釋放,形成和釋放過程中有時(shí)間消耗。這也就是遞歸有成本的原因。
遞歸核心思想講解
我們?cè)谄綍r(shí)中見過這個(gè)題目,叫做求字符串長(zhǎng)度。
這個(gè)我們可以用遞歸的寫法求解,順帶我們看下遞歸的核心。
首先假設(shè)我們求的字符為 "abcdefg123",我們用遞歸的解法可以轉(zhuǎn)化為,1+"bcdefg123",把"bcdefg123"進(jìn)而再轉(zhuǎn)化為1+"cdefg123",進(jìn)行求解,如圖示:
經(jīng)過一次次的大事化小,我們最后把問題變成了,求1+空字符串的長(zhǎng)度,這個(gè)其實(shí)也就是我們想要的遞歸出口,當(dāng)沒有字符時(shí)我們就該結(jié)束啦。
代碼如下:
int My_strlen(const char *str) { if (*str == '\0')//函數(shù)出口 { return 0; } return 1 + My_strlen(str + 1);//繼續(xù) } int main() { int len = My_strlen("abcdefg123"); printf("len = %d\n", len); return 0; }
遞歸的缺點(diǎn)
我們來看下遞歸的另外一個(gè)經(jīng)典例子,第n個(gè)菲波那切數(shù)列的實(shí)現(xiàn)
首先菲波那切數(shù)列是前兩個(gè)數(shù)之和等于第三個(gè)數(shù),第一個(gè)和第二個(gè)我們?cè)O(shè)定為1,那么這個(gè)數(shù)列為 1,1,2,3,5,8,13....等等,那我們要求第n個(gè)斐波那契數(shù)列的話,只要轉(zhuǎn)化為求前兩個(gè)數(shù)的和就好了,最后的遞歸出口為第一個(gè)或者第二個(gè)數(shù)時(shí)停止,結(jié)束函數(shù)。
代碼如下:求第十個(gè)菲波那切數(shù)
int fib(int n) { if (n == 1 || n == 2) { return 1; } return fib(n - 1) + fib(n - 2); } int main() { printf("fib(%d) = %d\n", 10, fib(10)); return 0; }
我們?nèi)绻蟮?n 的數(shù)字比較大就會(huì)非常慢。這個(gè)本質(zhì)就是上述說的成本問題。
如果求的是第42個(gè)菲波那切數(shù)呢?這次我們把時(shí)間也計(jì)算上。
int fib(int n) { if (n == 1 || n == 2) { return 1; } return fib(n - 1) + fib(n - 2); } int main() { int n = 42; double start = GetTickCount(); int x = fib(n); double end = GetTickCount(); printf("fib(%d) = %d count = %.1f S\n", n,x,(end - start)/1000); return 0; }
我們可以看出第42個(gè)時(shí)就已經(jīng)10秒了,這個(gè)很長(zhǎng)時(shí)間啦。我們用全局變量接收下次數(shù),那我們看看他計(jì)算了多少次第3個(gè)菲波那切數(shù)計(jì)算了幾次? 計(jì)算了大概1億多次,所以遞歸的重
復(fù)計(jì)算是非常多的。
我們看個(gè)圖示:
其中單單是第六個(gè)菲波那切數(shù)就計(jì)算了3次,這個(gè)就很夸張啦。
所以遞歸的特點(diǎn)是代碼簡(jiǎn)單,但是調(diào)用上可能會(huì)有大的成本。
最后一點(diǎn)就是:循環(huán)和遞歸是一定可以相互轉(zhuǎn)化的。只不過有些時(shí)候轉(zhuǎn)化會(huì)比較麻煩。
到此這篇關(guān)于C語言深入探索遞歸的特點(diǎn)的文章就介紹到這了,更多相關(guān)C語言遞歸內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用C語言實(shí)現(xiàn)“百馬百擔(dān)”問題方法示例
百馬百擔(dān)是道經(jīng)典的算法題,下面這篇文章主要給大家介紹了利用C語言實(shí)現(xiàn)“百馬百擔(dān)”問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12OpenCV實(shí)現(xiàn)特征檢測(cè)和特征匹配方法匯總
一幅圖像中總存在著其獨(dú)特的像素點(diǎn),這些點(diǎn)我們可以認(rèn)為就是這幅圖像的特征,成為特征點(diǎn),本文主要介紹了OpenCV實(shí)現(xiàn)特征檢測(cè)和特征匹配方法,感興趣的可以了解一下2021-08-08C語言中if語句加大括號(hào)和不加大括號(hào)的區(qū)別介紹
這篇文章主要給大家介紹了關(guān)于C語言中if語句加大括號(hào)和不加大括號(hào)的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12C++文件關(guān)鍵詞快速定位出現(xiàn)的行號(hào)實(shí)現(xiàn)高效搜索
這篇文章主要為大家介紹了C++文件關(guān)鍵詞快速定位出現(xiàn)的行號(hào)實(shí)現(xiàn)高效搜索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10C++實(shí)現(xiàn)猜數(shù)小游戲的實(shí)現(xiàn)
這篇文章主要介紹了C++實(shí)現(xiàn)猜數(shù)小游戲的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02