【C語言】——函數遞歸,用遞歸簡化并實現復雜問題

文章目錄

  • 前言
  • 一、什么是遞歸
  • 二、遞歸的限制條件
  • 三、遞歸舉例
    • 1.求n的階乘
    • 2. 舉例2:順序打印一個整數的每一位
  • 四、遞歸的優劣
  • 總結


前言

不多廢話了,直接開始。


一、什么是遞歸

遞歸是學習C語言函數繞不開的?個話題,那什么是遞歸呢?
遞歸其實是?種解決問題的方法,在C語言中,遞歸就是函數調用自己。
寫?個史上最簡單的C語言遞歸代碼:

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

上述就是一個簡單的遞歸程序,只不過上面的遞歸只是為了演示遞歸的基本形式,不是為了解決問題,代碼最終也會陷入死遞歸,導致棧溢出(Stack overflow)。

在這里插入圖片描述
遞歸的思想:
把一個大型復雜問題層層轉化為?個與原問題相似,但規模較小的子問題來求解;直到子問題不能再被拆分,遞歸就結束了。所以遞歸的思考方式就是把大事化小的過程。

遞歸中的遞就是遞推的意思,歸就是回歸的意思,接下來慢慢來體會。


二、遞歸的限制條件

遞歸在書寫的時候,有2個必要條件:

? 遞歸存在限制條件,當滿足這個限制條件的時候,遞歸便不再繼續。
? 每次遞歸調用之后越來越接近這個限制條件。

在下面的例子中,我們逐步體會這2個限制條件。


三、遞歸舉例

1.求n的階乘

計算n的階乘(不考慮溢出),n的階乘就是1~n的數字累積相乘。

分析和代碼實現:
我們知道n的階乘的公式: n! = n ? (n ? 1)!

舉例:
5! = 5×4×3×2×1
4! = 4×3×2×1
所以:
5! = 5×4!

這樣的思路就是把?個較大的問題,轉換為?個與原問題相似,但規模較小的問題來求解的。

n!—> n*(n-1)!
(n-1)! —> (n-1)*(n-2)!

直到n是1或者0時,不再拆解

再稍微分析?下,當 n<=1 的時候,n的階乘是1,其余n的階乘都是可以通過上述公式計算。 n的階乘的遞歸公式如下:
在這里插入圖片描述
那我們就可以寫出函數Fact求n的階乘,假設Fact(n)就是求n的階乘,那么Fact(n-1)就是求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;
}

運行結果(這里不考慮n太大的情況,n太大存在溢出):

在這里插入圖片描述
畫圖推演:

在這里插入圖片描述

2. 舉例2:順序打印一個整數的每一位

輸入?個整數m,打印這個按照順序打印整數的每?位。

比如:

輸入:1234 輸出:1 2 3 4
輸入:520 輸出:5 2 0

分析和代碼實現:

這個題目,放在我們面前,首先想到的是,怎么得到這個數的每一位呢?
如果n是?位數,n的每?位就是n自己
n是超過1位數的話,就得拆分每?位

1234%10就能得到4,然后1234/10得到123,這就相當于去掉了4
然后繼續對123%10,就得到了3,再除10去掉3,以此類推
不斷的 %10 和 \10 操作,直到1234的每一位都得到;
但是這里有個問題就是得到的數字順序是倒著的

但是我們有了靈感,我們發現其實?個數字的最低位是最容易得到的,通過%10就能得到那我們假設想寫?個函數Print來打印n的每?位,如下表示:

Print(n)
如果n是1234,那表示為
Print(1234) //打印1234的每?位
其中1234中的4可以通過%10得到,那么
Print(1234)就可以拆分為兩步:

  1. Print(1234/10) //打印123的每?位
  2. printf(1234%10) //打印4
    完成上述2步,那就完成了1234每?位的打印
    那么Print(123)?可以拆分為Print(123/10) + printf(123%10)

以此類推下去,就有

---- Print(1234)
==>Print(123) + printf(4)
==>Print(12) + printf(3)
==>Print(1) + printf(2)
==>printf(1)

直到被打印的數字變成?位數的時候,就不需要再拆分,遞歸結束。

代碼展示:

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;
}

輸入和輸出結果:

在這里插入圖片描述
在這個解題的過程中,我們就是使用了大事化小的思路
把Print(1234) 打印1234每?位,拆解為首先Print(123)打印123的每?位,再打印得到的4
把Print(123) 打印123每?位,拆解為首先Print(12)打印12的每?位,再打印得到的3
直到Print打印的是?位數,直接打印就行。

畫圖推演:
在這里插入圖片描述


四、遞歸的優劣

遞歸是?種很好的編程技巧,但它也有它的優點和缺點。

在C語言中每一次函數調用,都要需要為本次函數調用在棧區申請?塊內存空間來保存函數調用期間的各種局部變量的值,這塊空間被稱為運行時堆棧,或者函數棧幀。

函數不返回,函數對應的棧幀空間就?直占用,所以如果函數調用中存在遞歸調用的話,每?次遞歸函數調用都會開辟屬于自己的棧幀空間,直到函數遞歸不再繼續,開始回歸,才逐層釋放棧幀空間。

所以如果采用函數遞歸的方式完成代碼,遞歸層次太深,就會浪費太多的棧幀空間,也可能引起棧溢出(stack overflow)的問題。

如果用不了遞歸,一般通常用迭代(循環)的方法。

事實上,我們看到的許多問題是以遞歸的形式進行解釋的,這只是因為它比非遞歸的形式更加清晰, 但是這些問題的迭代實現往往比遞歸實現效率更高。

當?個問題非常復雜,難以使用迭代的方式實現時,此時遞歸實現的簡潔性便可以補償它所帶來的運行時開銷。


往期文章:c語言如何生成隨機數以及設置隨機數的范圍。(超詳細)

總結

碼字不易,點個關注和贊吧!!!
在這里插入圖片描述

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

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

相關文章

電商平臺商品銷量API接口,30天銷量API接口接口超詳細接入方案說明

電商平臺商品銷量API接口的作用主要是幫助開發者獲取電商平臺上的商品銷量信息。通過這個接口&#xff0c;開發者可以在自己的應用或網站中實時獲取商品的銷量數據&#xff0c;以便進行銷售分析、庫存管理、市場預測等操作。 具體來說&#xff0c;電商平臺商品銷量API接口的使…

RocketMq集成SpringBoot(待完善)

環境 jdk1.8, springboot2.7.3 Maven依賴 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.3</version><relativePath/> <!-- lookup parent from…

vue3 筆記 - 聲明式 一

官網&#xff1a;Vue.js - 漸進式 JavaScript 框架 | Vue.js vue3編寫有聲明式和響應式。該文章僅記錄聲明式。vue3聲明式與vue2相同。 一、生命周期 創建之前 beforeCreate()已創建 created()掛載之前 beforeMount()已掛載 mounted()銷毀之前 beforeUnmount()已銷毀 unmoun…

java面試-Dubbo和zookeeper運行原理

遠離八股文&#xff0c;面試大白話&#xff0c;通俗且易懂 看完后試著用自己的話復述出來。有問題請指出&#xff0c;有需要幫助理解的或者遇到的真實面試題不知道怎么總結的也請評論中寫出來&#xff0c;大家一起解決。 java面試題匯總-目錄-持續更新中 分布式注冊中心和服務調…

Unity中后處理簡介

文章目錄 前言一、后處理的原理二、我們看一下Unity文檔中&#xff0c;內置的后處理前后的效果后處理前&#xff1a;后處理后&#xff1a; 前言 我們在這篇文章中&#xff0c;了解一下Unity中的后處理效果 后期處理概述 一、后處理的原理 在后處理的過程中&#xff0c;我們主…

Java當中常用的算法

文章目錄 算法二叉樹左右變換數據二分法實現 冒泡排序算法插入排序算法快速排序算法希爾排序算法歸并排序算法桶排序算法基數排序算法分治算法漢諾塔問題動態規劃算法引子代碼實現背包問題 KMP算法什么是KMP算法暴力匹配KMP算法實現 今天我們來看看常用的算法&#xff0c;開干。…

《微信小程序開發從入門到實戰》學習四十五

4.4 云函數 云函數是開發者提前定義好的、保存在云端并且將在云端運行的JS函數。 開發者先定義好云函數&#xff0c;再使用微信開發工具將云函數上傳到云空間&#xff0c;在云開發控制臺中可看到已經上傳的云函數。 云函數運行在云端Node.js環境中。 小程序端通過wx.cloud.…

IP地址定位技術為網絡安全建設提供全新方案

隨著互聯網的普及和數字化進程的加速&#xff0c;網絡安全問題日益引人關注。網絡攻擊、數據泄露、欺詐行為等安全威脅層出不窮&#xff0c;對個人隱私、企業機密和社會穩定構成嚴重威脅。在這樣的背景下&#xff0c;IP地址定位技術應運而生&#xff0c;為網絡安全建設提供了一…

Python Selenium 自動登入1688

Python Selenium是一個用于自動化Web瀏覽器操作的庫。它提供了一組功能強大的工具和API&#xff0c;可以模擬用戶在瀏覽器中的行為&#xff0c;并執行各種任務&#xff0c;如點擊、輸入文本、提交表單等。 要使用Python Selenium登錄1688網站&#xff0c;需要進行以下步驟&…

iOS微信小程序虛擬支付解決方案

眾所周知&#xff0c;在IOS微信小程序不支持虛擬支付&#xff0c;一直是困擾IOS開發者、運營最頭疼的問題&#xff0c;主要原因是蘋果不允許IOS微信上架這類產品。導致微信小程序的開發者在IOS上都不能支付虛擬商品&#xff0c;虛擬商品包含了虛擬課程、會員、虛擬書等。 那么…

短視頻ai剪輯分發矩陣系統源碼3年技術團隊開發搭建打磨

如果您需要搭建這樣的系統&#xff0c;建議您尋求專業的技術支持&#xff0c;以確保系統的穩定性和安全性。 在搭建短視頻AI剪輯分發矩陣系統時&#xff0c;您需要考慮以下幾個方面&#xff1a; 1. 技術實現&#xff1a;您需要選擇適合您的需求和預算的技術棧&#xff0c;例如使…

肖sir__ 項目講解__項目數據

項目時間&#xff1a; 情況一&#xff1a;項目時間開始到上線的時間&#xff0c;這個時間一般比較長&#xff08;一年&#xff0c;二年&#xff0c;三年&#xff09; 情況二&#xff1a;項目的版本的時間或則是周期&#xff08;1個月&#xff0c;2個月&#xff0c;3個月&…

機器人、智能小車常用的TT電機/310電機/370電機選型對比

在制作智能小車或小型玩具時&#xff0c;在電機選型上一些到各種模糊混淆的概念&#xff0c;以及各種錯綜復雜的電機參數&#xff0c;本文綜合對比幾種常用電機的參數及特性適應范圍&#xff0c;以便快速選型&#xff0c;注意不同生產廠家的電機參數規則會有較大差異。 普通TT…

論文閱讀:PointCLIP: Point Cloud Understanding by CLIP

CVPR2022 鏈接&#xff1a;https://arxiv.org/pdf/2112.02413.pdf 0、Abstract 最近&#xff0c;通過對比視覺語言預訓練(CLIP)的零鏡頭學習和少鏡頭學習在2D視覺識別方面表現出了鼓舞人心的表現&#xff0c;即學習在開放詞匯設置下將圖像與相應的文本匹配。然而&#xff0c;…

【ET8】2.ET8入門-ET框架解析

菜單欄相關&#xff1a;ENABLE_DLL選項 ET->ChangeDefine->ADD_ENABLE_DLL/REMOVE_ENABLE_DLL 一般在開發階段使用Editor時需要關閉ENABLE_DLL選項。該選項關閉時&#xff0c;修改腳本之后&#xff0c;會直接重新編譯所有的代碼&#xff0c;Editor在運行時會直接使用最…

免費網頁抓取工具大全【附下載和工具使用教程】

在當今信息爆炸的時代&#xff0c;獲取準確而豐富的數據對于企業決策和個人研究至關重要。而網頁抓取工具作為一種高效獲取互聯網數據的方式&#xff0c;正逐漸成為大家解決數據需求的得力助手。本文將深入探討網頁抓取工具的種類&#xff0c;并為大家提供簡單實用的頁面采集教…

(企業項目)SpringBoot3整合校驗框架validation

在Spring Boot項目中使用校驗框架validation可以讓我們更方便地實現數據校驗和錯誤提示。下面是Spring Boot集成校驗框架validation的步驟。 添加依賴 在項目的pom.xml文件中添加validation依賴&#xff1a; <dependency><groupId>org.springframework.boot</…

C# 實現Lru緩存

C# 實現Lru緩存 LRU 算法全稱是最近最少使用算法&#xff08;Least Recently Use&#xff09;&#xff0c;是一種簡單的緩存策略。 通常用在對象池等需要頻繁獲取但是又需要釋放不用的地方。 代碼實現的基本原理就是使用鏈表&#xff0c;當某個元素被訪問時&#xff08;Get或…

windows安裝protoc、protoc-gen-go、protoc-gen-go-grpc

文章目錄 一、 protoc二、protoc-gen-go三、protoc-gen-go-grpc 一、 protoc 1&#xff0c;下載&#xff1a;https://github.com/google/protobuf/releases 下載對應的protoc&#xff0c;注意選擇windows 2&#xff0c;下好之后解壓就行&#xff0c;然后把bin目錄加入到環境…

【異常】淺析異常體系及為什么一定會執行finally塊代碼

異常體系&#xff1a; &#xff08;1&#xff09;所有異常&#xff08;Exception&#xff09;、錯誤&#xff08;Error&#xff09;都繼承自異常中的基類&#xff1a;Throwable。而異常又可以分為檢查異常&#xff08;Checked Exception&#xff09;、非檢查異常&#xff08;Un…