C語言中的套娃——函數遞歸

目錄

一、什么是遞歸

1.1.遞歸的思想

1.2.遞歸的限制條件

二、舉例體會

2.1.求n的階乘?

2.2.順序打印整數的每一位

2.3.斐波那契數列

三、遞歸與迭代


一、什么是遞歸

在學習C語言的過程中,我們經常會跟遞歸打交道,什么是遞歸呢?它其實是一種解決問題的方法,遞歸遞歸,顧名思義,遞推回歸。在C語言中,函數自己調用自己就是遞歸,我們可以把它想成生活中的俄羅斯套娃。

下面請看最簡單的遞歸代碼:

#include <stdio.h>
int main()
{printf("hehe\n");main();//main函數中?調?了main函數return 0;
}

在上面的代碼中,我們看到了main函數里再次調用了main函數,我們可以想象,這個程序會一直調用下去,直到,內存不夠導致棧溢出(Stack overflow)。

1.1.遞歸的思想

遞歸的思想用一個詞來講就是“大事化小”。

其中代表遞推代表回歸。

1.2.遞歸的限制條件

剛剛我們看到,一直調用main函數的話,會造成死遞歸,因此,我們在使用遞歸時需要注意一些必要條件。

1.遞歸存在限制條件,當超過這個限制條件時遞歸就應該停止

2.每次遞歸應該越來越接近這個限制條件。?

接下來我們舉幾個例子來讓大家體會一下這兩個必要條件。

二、舉例體會

2.1.求n的階乘?

?個正整數的階乘(factorial)是所有?于及等于該數的正整數的積,并且0的階乘為1。
?
自然數n的階乘寫作 n! 。

經分析可知n! = n * (n-1) * (n-2)... * 3 * 2 * 1,而(n-1)! = (n-1) * (n-2) *...* 3 * 2 * 1。

所以n! = n * (n-1)!。

我們要求n的階乘,只需要求n和n-1的階乘的乘積,問題也就變成了求n-1的階乘。經過一次遞歸,我們就從n變到n-1,那遞歸的次數足夠了,我們就可以到最后的1的階乘。那怎么得到n的階乘呢,我們剛剛一步一步得到1的階乘,那我們再一步一步乘回去,最終得到n的階乘。

上述思路就是所謂的遞歸,也就是把一個較大的問題轉換為與原問題相似的小問題。

當n = 0時,n! = 1。我們可以得到遞推公式:

代碼如下:

函數部分

int Fact(int n)
{if(n==0)return 1;elsereturn n*Fact(n-1);
}

總體

#include <stdio.h>
int Fact(int n)
{if(n==0)return 1;elsereturn n*Fact(n-1);
}
int main()
{int n = 0;scanf("%d", &n);int ret = Fact(n);printf("%d\n", ret);return 0;
}

測試結果

2.2.順序打印整數的每一位

輸入一個整數n,順序打印其每一位。

input : 1234

output : 1 2 3 4

分析可知,1234/10 = 123,而1234%10 = 4。那我們可以巧妙的利用上述特性,得到1234的每一位。但是出現一個問題,我們獲得的數字的順序是倒著的,這該怎么辦呢。我們可以仔細品味一下遞歸,遞推和回歸,先遞推再回歸。

我們就可以先進行/10的操作,再打印%10的余數,如下:

void Print(int n)
{if(n>9){Print(n/10);}printf("%d ", n%10);
}

畫圖推演一下:

代碼如下:

#include<stdio.h>
void Print(int n)
{if (n > 9){Print(n / 10);}printf("%d ", n % 10);
}
int main()
{int m = 0;scanf("%d", &m);Print(m);return 0;
}

運行結果:

2.3.斐波那契數列

斐波那契數列(Fibonacci sequence),又稱黃金分割數列,因數學家萊昂納多·斐波那契(Leonardo Fibonacci)以兔子繁殖為例子而引入,故又稱“兔子數列”,其數值為:1、1、2、3、5、8、13、21、34……?

其遞推公式為

用遞推寫出代碼很簡單:

#include<stdio.h>int Fib(int n) 
{if (n == 1 || n == 2)return 1;else return Fib(n - 1) + Fib(n - 2);
}int main()
{int n = 0;scanf("%d", &n);printf("%d", Fib(n));return 0;
}

運行結果:

那如果讓你不用遞歸的方法,你會怎么做呢??

我們可以創建三個變量,就像兩個數互相交換那樣,將a賦值1,b賦值1,c為a與b的和。

n大于二之后才開始循環,所以我們可以這么寫:

int Fib(int n) 
{int a = 1, b = 1,c = 0;while (n>2){c = a + b;a = b;b = c;n--;}return b;
}

?一個接著一個交換值,直到n等于2,退出循環,此時c的值賦給了b,而我們在n小于等于2的時候,求不出來c,而b的值正好是1,所以我們返回b的值。

三、遞歸與迭代

上面我們說了什么是遞歸,這又來個迭代,什么叫迭代呢?說白了通常就是循環。

比如剛才計算階乘,我就不想用遞歸,那我就循環n次,也可以解決問題,并且該方法效率比遞歸高。

我們遇到的許多問題用遞歸解釋的原因是因為,它比非遞歸好想好解釋,但這些問題往往迭代比遞歸的效率更高。

我們說當一個問題非常復雜,難以用迭代的方式來解決時2,這時候遞歸實現的簡潔性便可以補償運行時的開銷。

就像剛剛的例三,求斐波那契數列,使用迭代的方法就更加有效率。

如圖所示,遞歸層次越深,冗余計算越多,我們可以簡單測試一下

#include <stdio.h>
int count = 0;
int Fib(int n)
{if(n == 3)count++;//統計第3個斐波那契數被計算的次數if(n<=2)return 1;elsereturn Fib(n-1)+Fib(n-2);
}
int main()
{int n = 0;scanf("%d", &n);int ret = Fib(n);printf("%d\n", ret); printf("\ncount = %d\n", count);return 0;
}

?來看結果

這才是40,可想而知50會是多大的天文數字。

而迭代的方式,我們只需要前后一步一步相加即可。


最后總結一下,遞歸是一個很好的解決問題方式,在編程學習中,我們會經常用到它,但是它也不是萬能的,還是需要我們多動腦思考。

我相信,我們總會找到解決辦法的。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/715895.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/715895.shtml
英文地址,請注明出處:http://en.pswp.cn/news/715895.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

LNMP 架構

環境準備&#xff1a;lnmp 需要安裝 nginx mysql php 論壇/博客 軟件 使用LNMP架構搭建 論壇 1. 關閉防火墻和和核心防護 systemctl disable --now firewalld setenforce 0 2. 編譯安裝 nginx 安裝依賴包 yum -y install pcre-devel zlib-devel gcc gcc-c make 創建…

在Redhat 7 Linux上安裝llama.cpp [ 錯誤stdatomic.h: No such file or directory]

前期準備 在github上下載llama.cpp或克隆。 GitHub - ggerganov/llama.cpp: LLM inference in C/C ? git clone https://github.com/ggerganov/llama.cpp.gitcd llama.cpp 執行make命令編譯llama.cpp make 在huggingface里下載量化了的 gguf格式的llama2模型。 https:/…

每日一練:筆試題復盤-LeeCode原題-判斷二叉樹兩數之和-->找到滿足二叉樹兩數之和的所有路徑

用Java實現&#xff0c;給定一個二叉樹root和一個值 sum &#xff0c;找到從根節點到葉子節點的節點值之和等于 sum 的路徑。 1.該題路徑定義為從樹的根結點開始往下一直到葉子結點所經過的結點 2.葉子節點是指沒有子節點的節點 3.路徑只能從父節點到子節點&#xff0c;不能從子…

Compiling from source on UNIX(cmake doxygen ant maven ccache)

前言 源碼鏈接 cmake-3.18.0 https://cmake.org/files/v3.18/cmake-3.18.0.tar.gzdoxygen-1.10.0 https://www.doxygen.nl/files/doxygen-1.10.0.src.tar.gzapache-ant-1.10.8-bin https://archive.apache.org/dist/ant/binaries/apache-ant-1.10.8-bin.tar.gzapache-maven-3…

#WEB前端(表單)

1.實驗&#xff1a; form、input、label 登錄界面&#xff0c;表單填寫界面 2.IDE&#xff1a;VSCODE 3.記錄&#xff1a; 4.代碼&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name&q…

RedisTemplate中opaForValue.set的注意之處

問題 原本寫了一個小項目&#xff0c;想通過redis緩存實現登錄退出功能&#xff0c;結果出現了莫名奇妙的問題 代碼如下&#xff1a; 報錯&#xff1a; 經過多次調試之后我發現是opsForValue.set(key,value,expireTime)這行代碼的問題&#xff0c;沒有指定過期時間的單位&…

備戰藍橋杯---動態規劃之懸線法

Em...屬于一知道就會&#xff0c;不知道的話比較難想。 我們先看題&#xff1a; 我們不妨把1抽象成一個平面上的點&#xff0c;因此可以變成這一幅圖&#xff1a; 我們假設每一個點被向上牽拉了一根線&#xff1a; 顯然&#xff0c;每一條懸線都有可能成為邊界限制&#xff0c…

JS值和引用

在javaScript中&#xff0c;數據類型整體上可以分為兩大類&#xff1a;基本數據類型和引用數據類型 基本數據類型&#xff1a; string , symbol , number , boolean , undefined , null 引用數據類型&#xff1a; object 1.簡單值&#xff08;原始值&#xff09; 由于簡單…

職業生涯知識回顧-關于抽象類和接口的思考

抽象類和接口是兩個很容易產生疑惑的概念&#xff0c;分不清它們的使用場景&#xff0c;其實只要記住兩點就比較好理解&#xff1a; 接口是對行為的抽象抽象類是對子類有哪些屬性和行為的抽象 當你需要對一個類有哪些行為進行約束時&#xff0c;使用接口&#xff1b;需要為其…

Bulingbuling - 《歷史的教訓》 [ The Lessons of History ]

《歷史的教訓》 兩位當代最偉大思想家的著名論文集&#xff0c;匯集了 5000 多年的歷史 作者&#xff1a;威爾-杜蘭特和阿里爾-杜蘭特 The Lessons of History The celebrated collection of essays compiling over 5,000 years of history by two of the greatest thinkers …

Spring Boot項目中不使用@RequestMapping相關注解,如何動態發布自定義URL路徑

一、前言 在Spring Boot項目開發過程中&#xff0c;對于接口API發布URL訪問路徑&#xff0c;一般都是在類上標識RestController或者Controller注解&#xff0c;然后在方法上標識RequestMapping相關注解&#xff0c;比如&#xff1a;PostMapping、GetMapping注解&#xff0c;通…

Siamrpn++論文中文翻譯(詳細!)

SiamRPN: Evolution of Siamese Visual Tracking with Very Deep Networks SiamRPN&#xff1a;具有非常深度網絡的Siamese視覺跟蹤的進化 【siamrpn論文地址】 https://arxiv.org/abs/1812.11703 摘要 基于Siamese網絡的跟蹤器將跟蹤表示為目標模板和搜索區域之間的卷積特征…

【STA】多場景時序檢查學習記錄

單周期路徑 建立時間時序檢查 在時鐘的有效沿到達觸發器之前&#xff0c;數據應在一定時間內保持穩定&#xff0c;這段時間即觸發器的建立 時間。滿足建立時間要求將確保數據可靠地被捕獲到觸發器中。 建立時間檢查是從發起觸發器中時鐘的第一個有效沿到捕獲觸發器中時鐘后面…

理解大模型的5個關鍵公式

理解大模型的5個關鍵公式_嗶哩嗶哩_bilibili PPT&#xff1a;https://link.excalidraw.com/p/readonly/aBWlNjEckdUlrszwwo6V

基于springboot+vue的社區醫院管理系統

博主主頁&#xff1a;貓頭鷹源碼 博主簡介&#xff1a;Java領域優質創作者、CSDN博客專家、阿里云專家博主、公司架構師、全網粉絲5萬、專注Java技術領域和畢業設計項目實戰&#xff0c;歡迎高校老師\講師\同行交流合作 ?主要內容&#xff1a;畢業設計(Javaweb項目|小程序|Pyt…

chatgpt-3的文章生成器有哪些?可以批量生成文章的生成器

GPT-3&#xff08;Generative Pre-trained Transformer 3&#xff09;作為人工智能領域的一項重大突破&#xff0c;開啟了新一代的文本生成技術。同時市面上也涌現出了一些GPT-3文章生成器&#xff0c;為用戶提供了快速、高效地生成各種類型文章的工具。本文將介紹一些中國的GP…

unity-unity2d基礎操作筆記(三)0.5.000

目標是:牢記以下137條操作,越級上升到中級階段 unity-unity2d基礎操作筆記(三) 一百零一、如何操作一個游戲物體由多個部分組成的動畫一百零二、如何使用rigidbody 2d進行物體移動一百零三、獲取游戲物體身上的組件方法一百零四、代碼控制物體朝向一百零五、不使用插件,純…

C#上位機調試經驗

1.使用Visual Studio的遠程工具 因為上位機軟件安裝在工控機上&#xff0c;不方便調試。如果直接把代碼放在工控機上&#xff0c;又不太安全。 可以在工控機上安裝一個Visual Studio的遠程工具&#xff0c;把隨身帶的筆記本電腦通過網線插在工控機上 這樣可以在筆記本上使用…

s3cmd工具使用

1. 安裝s3cmd工具 [roottestserver01 ~]# yum install s3cmd 2. 配置s3cmd, 按提示輸入相應的ak&#xff0c;sk&#xff0c;endpoint等信息 [roottestserver01 ~]# s3cmd --configure 3. s3cmd使用 [roottestserver01 ~]# s3cmd mb s3://abc &#xff08;創建一個桶&am…

python筆記_程序流程控制

A&#xff0c;順序控制 程序從上到下逐行執行 python定義變量時&#xff0c;會合法地向前引用 age 1 age2 age 1 age2 age 1 age 1 ——>錯誤&#xff0c;age應在age2之前 B&#xff0c;分支控制 1&#xff0c;單分支if 語法 if 條件表達式 &#xff1a; 代碼塊 說明…