C語言--遞歸

在這里插入圖片描述

曾經有一個段子:上大學時,我們的c語言老師說:學c時,如果有50%的同學死在了循環上面,那么就有90%的同學死在了遞歸上面。接下來,就來看看遞歸是怎么個事?

一.遞歸的介紹

遞歸是指一個函數直接或間接調用自身的過程。在編程中,遞歸通常用于解決可以被分解為相似子問題的任務。

  1. 基本原理:遞歸函數通過反復調用自身來解決問題,每次調用都會解決一個規模較小的子問題,直到達到遞歸的終止條件。

  2. 遞歸函數的結構

    • 基本情況(終止條件):遞歸函數需要定義一個或多個基本情況,這些情況下遞歸調用不再發生,避免無限循環。
    • 遞歸情況:在遞歸情況下,函數調用自身來解決同一問題的子問題。
  3. 遞歸與循環:遞歸和迭代循環(for、while循環)都可以實現相同的算法,但遞歸通常更簡潔,易于理解,有時更符合問題的自然表達方式。

  4. 遞歸的應用:遞歸廣泛用于數據結構==(如樹、圖等)的遍歷和搜索==,例如深度優先搜索(DFS)和快速排序算法。

  5. 性能考慮遞歸可能會消耗大量的棧空間,因為每次函數調用都會在棧上分配一個新的棧幀。這在處理大規模問題時需要注意,可以通過優化算法或者尾遞歸優化來減少內存消耗。

  6. 遞歸的優缺點

    • 優點:簡潔、清晰表達某些問題的解決方式。
    • 缺點:可能會因為調用層次過深導致棧溢出,性能上可能不如迭代循環。

二.什么是棧幀

棧幀(Stack Frame),也稱為活動記錄(Activation Record)或者幀(Frame),是在函數調用過程中在程序運行時棧上的一個特定區域,用于存儲與當前函數調用相關的信息和數據。每當一個函數被調用時,系統就會為該函數在棧上分配一個新的棧幀,用于管理函數的局部變量、參數、返回地址以及其他執行上下文信息。

棧幀通常包括以下主要部分:

  1. 局部變量:函數內部聲明的局部變量會被存儲在棧幀中。這些變量的生命周期與函數的調用周期相關聯,在函數調用結束時,這些變量的存儲空間也會自動釋放。

  2. 參數:調用函數時傳遞的參數值被存儲在棧幀中,供函數體內部使用。

  3. 返回地址:函數調用完成后,程序需要返回到調用該函數的下一條指令的地址。返回地址存儲在棧幀中,使得程序可以正確地返回到調用點繼續執行。

  4. 其他管理信息:棧幀還可能包括調試信息、異常處理信息等,這些信息有助于程序的正確執行和調試。

棧幀的創建和銷毀遵循后進先出(LIFO)原則,即最后進入棧的棧幀最先被釋放。這種機制保證了函數調用的嵌套順序正確,同時也控制了函數調用過程中的內存管理。

理解和正確使用棧幀是編寫函數式程序的關鍵,尤其是在處理遞歸函數或者多層函數調用時,對棧幀的合理利用可以提高程序的效率和可靠性。

舉例說明

有 5 個學生坐在一起, 問第 5 個學生多少歲?他說比第 4 個學生大 2歲,問第 4 個學生歲數,他說比第 3 個學生大 2 歲,問第 3 個學生,又說比第 2個學生大 2 歲,問第 2 個學生,說比第 1 個學生大 2 歲,最后問第 1 個學生,他說是 10 歲,請問第 5 個學生多大。
該問題如果使用非遞歸,代碼如下:

//非遞歸求年齡
int Age1(int n)
{int tmp = 10; //第一個人年齡for(int i=1;i<n;i++){tmp += 2;//后面的人比前一個多 2 歲}return tmp;
}

那么遞歸該如何處理呢?我們先分析一下:
如果 Age 函數是用來求年齡的,那么
Age(1)表示第一個人的年齡;
Age(2)表示第二個人的年齡;

Age(n-1)表示第 n-1 個人的年齡;
Age(n)表示第 n 個人的年齡。
上面的這些能理解,下面的程序就好理解了

//遞歸求年齡
int Age(int n)
{int tmp;//保存年齡if (n == 1)tmp = 10;elsetmp = Age(n - 1) + 2;//當前第 n 個比第 n-1 個年齡多 2return tmp;
}

在這里插入圖片描述
上圖中的紅色表示函數的調用過程,在這個過程中每個函數都還沒有執行完成,那么每個函數占用的內存空間都不能釋放,函數的調用都需要占用一定的棧空間(一個棧幀),而棧的空間是非常小的(在動態內存章節講過棧 1M),當遞歸次數非常多時有可能出現棧空間不足

在這里插入圖片描述

// 遞歸求年齡
int Age(int n)
{int tmp;//保存年齡if (n == 1)tmp = 10;elsetmp = Age(n - 1) + 2;//當前第 n 個比第 n-1 個多 2return tmp;//return n == 1 ? 10 : Age(n - 1) + 2;//等同上面的代碼
}//遞歸調用次數太多, 程序崩潰
int main()
{printf("%d\n", Age1(5000));//可以.利用循環求解//printf("%d\n",Age(5000));//崩潰,棧溢出,遞歸次數太多,超過棧容量return 0;
}

在這里插入圖片描述

例2.求階乘

利用遞歸求階乘 n!
算法分析:可以利用下面公式求階乘

在這里插入圖片描述

long long Fac(int n)
{if (n == 0 || n == 1)return 1;return n * Fac(n - 1);
}

在這里插入圖片描述

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

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

相關文章

Spring中的@Transactional什么時候會失效?

在Spring中&#xff0c;Transactional注解用于聲明式事務管理&#xff0c;它可以使方法在事務上下文中執行。然而&#xff0c;Transactional注解有時會失效&#xff0c;這通常是由于以下幾種情況&#xff1a; 1. 非public方法&#xff1a; - Transactional注解默認只能應用…

跨平臺WPF音樂商店應用程序

目錄 一 簡介 二 設計思路 三 源碼 一 簡介 支持在線檢索音樂&#xff0c;支持實時瀏覽當前收藏的音樂及音樂數據的持久化。 二 設計思路 采用MVVM架構&#xff0c;前后端分離&#xff0c;子界面彈出始終位于主界面的中心。 三 源碼 視窗引導啟動源碼&#xff1a; namesp…

MySQL(8)事務

目錄 1.事務; 1.事務: 1.1 如果CURD不加限制會這么樣子? 可能造成數據同時被修改, 數據修改的結果是未知的.(可以想一下之前的搶票線程問題) 1.2 事務概念: 事務就是一組DML語句組成&#xff0c;這些語句在邏輯上存在相關性&#xff0c;這一組DML語句要么全部成功&#xff0…

基于python旅游景點滿意度分析設計與實現

1.1研究背景與意義 1.1.1研究背景 隨著旅游業的快速發展&#xff0c;滿意度分析成為評估旅游景點質量和提升游客體驗的重要手段。海口市作為中國的旅游城市之一&#xff0c;其旅游景點吸引了大量游客。然而&#xff0c;如何科學評估和提升海口市旅游景點的滿意度&#xff0c;…

中電金信-杭州工商銀行|面試真題|2024年

中電金信-杭州工商銀行 JAva集合用過哪些? ArrayList、LinkedList、HashSet、TreeSet、HashMap、LinkedHashMap、ConcurrentHashMap Arraylist和linkbist區別 ArrayList底層是數據&#xff0c;查詢快&#xff0c;增刪慢&#xff0c;線程不安全&#xff0c;效率高LikedList 底…

【概率論三】參數估計:點估計(矩估計、極大似然法)、區間估計

文章目錄 一. 點估計1. 矩估計法2. 極大似然法2.1. 似然函數2.2. 極大似然估計法 3. 評價估計量的標準3.1. 無偏性3.2. 有效性3.3. 一致性 二. 區間估計1. 區間估計的概念2. 正態總體參數的區間估計 參數估計講什么 由樣本來確定未知參數參數估計分為點估計與區間估計 一. 點估…

算法:二叉樹相關

目錄 題目一&#xff1a;單值二叉樹 題目二&#xff1a;二叉樹的最大深度 題目三&#xff1a;相同的樹 題目四&#xff1a;對稱二叉樹 題目五&#xff1a;另一棵樹的子樹 題目六&#xff1a;二叉樹的前序遍歷 題目七&#xff1a;二叉樹遍歷 題目八&#xff1a;根據二叉…

linux搭建mysql主從復制(一主一從)

目錄 0、環境部署 1、主服務器配置 1.1 修改mysql配置文件 1.2 重啟mysql 1.3 為從服務器授權 1.4 查看二進制日志坐標 2、從服務器配置 2.1 修改mysql配置文件 2.2 重啟mysql 2.3 配置主從同步 2.4 開啟主從復制 3、驗證主從復制 3.1 主服務器上創建test…

微服務拆分流程 (黑馬商城拆分商品服務)

1. 創建新module - maven模塊&#xff0c;并引入依賴&#xff08;可以復制 把不需要的依賴刪掉 &#xff09; 2. 新建包com.hmall.xx&#xff08;業務名&#xff09;&#xff0c;添加和修改啟動類&#xff0c;新建mapper包、domain包 - service包 - controller包 3. 拷貝并修…

4款良心軟件,免費又實用,內存滿了都舍不得卸載

以下幾款高質量軟件&#xff0c;若是不曾體驗&#xff0c;實在是遺憾可惜。 PDF Guru 這是一款開源免費的PDF編輯軟件&#xff0c;打開之后功能一目了然。 可以拆分、合并PDF&#xff0c;也可以給PDF添加水印和密碼&#xff0c;同時也可以去除別人PDF里的水印或密碼&#xff0…

HouseCrafter:平面草稿至3D室內場景的革新之旅

在室內設計、房地產展示和影視布景設計等領域,將平面草稿圖快速轉換為立體的3D場景一直是一個迫切的需求。HouseCrafter,一個創新的AI室內設計方案,正致力于解決這一挑戰。本文將探索HouseCrafter如何將這一過程自動化并提升至新的高度。 一、定位:AI室內設計的革新者 Ho…

Scala之OOP講解

Scala OOP 前序 Scala 為純粹OOP1、不支持基本類型&#xff1a;一切皆為對象 Byte,Int,...2、不支持靜態關鍵字&#xff1a;static 3、支持類型推斷【通過判斷泛型的父子關系來確定泛型類的父子關系>協變&#xff0c;逆變&#xff0c;不變】和類型預定&#xff0c; 動靜…

【iOS】類對象的結構分析

目錄 對象的分類object_getClass和class方法isa流程和繼承鏈分析isa流程實例驗證類的繼承鏈實例驗證 類的結構cache_t結構bits分析實例驗證屬性properties方法methods協議protocolsro類方法 類結構流程圖解 對象的分類 OC中的對象主要可以分為3種&#xff1a;實例對象&#xf…

【React】JSX基礎

一、簡介 JSX是JavaScript XML的縮寫&#xff0c;它是一種在JavaScript代碼中編寫類似HTML模板的結構的方法。JSX是React框架中構建用戶界面&#xff08;UI&#xff09;的核心方式之一。 1.什么是JSX JSX允許開發者使用類似HTML的聲明式模板來構建組件。它結合了HTML的直觀性…

TDesign組件庫日常應用的一些注意事項

【前言】Element&#xff08;餓了么開源組件庫&#xff09;在國內使用的普及率和覆蓋率高于TDesign-vue&#xff08;騰訊開源組件庫&#xff09;&#xff0c;這也導致日常開發遇到組件使用上的疑惑時&#xff0c;網上幾乎搜索不到其文章解決方案&#xff0c;只能深挖官方文檔或…

2024.7.17 ABAP面試題目總結

2024.7.17 用的SAP什么平臺&#xff0c;S4/HANA嗎&#xff0c;有用過ECC嗎 S4/HANA&#xff0c;沒用過ECC 會不會CDS VIEW 不會 會不會FIORI 不會 銀企直連里面的邏輯了解不 不了解&#xff0c;做過&#xff0c;但是只能算很簡單的修改 SAP做增強&#xff0c;如何創建…

網絡安全-網絡安全及其防護措施7

31.防病毒和惡意軟件保護 防病毒和惡意軟件防護的定義和作用 防病毒和惡意軟件防護是一種保護計算機和網絡免受病毒、木馬、間諜軟件等惡意軟件侵害的安全措施。通過防護措施&#xff0c;可以檢測、阻止和清除惡意軟件&#xff0c;確保系統和數據的安全。其主要作用包括&…

C++右值引用和移動語義

目錄 概念&#xff1a; 左值引用和右值引用 概念&#xff1a; 注意&#xff1a; 左值引用的意義 作函數參數 函數引用返回 右值引用的意義 誕生背景 移動構造 移動賦值 其他應用 萬能引用和完美轉發 默認的移動構造和移動賦值 概念&#xff1a; 左值&#xff1a;顧…

List數據的幾種數據輸出方式

一、問題引入 在Java中&#xff0c;查詢List集合是一項常見的任務&#xff0c;它可以通過多種方式實現&#xff0c;以滿足不同的需求。下面&#xff0c;List數據的幾種數據輸出方式。 二、實例 /*** 查詢所有用戶信息* return*/ List<User> getAllUser(); <select…

Git【撤銷遠程提交記錄】

在實際開發中&#xff0c;你是否遇到過錯誤的提交了代碼&#xff0c;想要刪掉本次提交記錄的情況&#xff0c;你可以按照如下方法實現。 1、使用 git revert 如果你想要保留歷史記錄&#xff0c;并且對遠程倉庫其他使用者的影響最小&#xff0c;你可以使用 git revert 命令。這…