C语言递归函数(递归调用)详解

news2024/11/16 9:22:49

一个函数在它的函数体内调用它自身称为递归调用,这种函数称为递归函数。执行递归函数将反复调用其自身,每调用一次就进入新的一层,当最内层的函数执行完毕后,再一层一层地由里到外退出。

递归函数不是C语言的专利,Java、C#、JavaScript、PHP 等其他编程语言也都支持递归函数。

下面我们通过一个求阶乘的例子,看看递归函数到底是如何运作的。阶乘 n! 的计算公式如下:

根据公式编写如下的代码:

#include<stdio.h>

//求n的阶乘
longfactorial(int n){
if(n ==0|| n ==1){
return1;
}
else{
returnfactorial(n -1)* n;// 递归调用
}
}

intmain(){
int a;
printf("Input a number: ");
scanf("%d",&a);
printf("Factorial(%d) = %ld\n", a,factorial(a));

return0;
}

运行结果:

Input a number: 5

Factorial(5) = 120

factorial() 就是一个典型的递归函数。调用 factorial() 后即进入函数体,只有当 n==0 或 n==1 时函数才会执行结束,否则就一直调用它自身。

由于每次调用的实参为 n-1,即把 n-1 的值赋给形参 n,所以每次递归实参的值都减 1,直到最后 n-1 的值为 1 时再作递归调用,形参 n 的值也为1,递归就终止了,会逐层退出。

要想理解递归函数,重点是理解它是如何逐层进入,又是如何逐层退出的,下面我们以 5! 为例进行讲解。

递归的进入

1) 求 5!,即调用 factorial(5)。当进入 factorial() 函数体后,由于形参 n 的值为 5,不等于 0 或 1,所以执行factorial(n-1) * n,也即执行factorial(4) * 5。为了求得这个表达式的结果,必须先调用 factorial(4),并暂停其他操作。换句话说,在得到 factorial(4) 的结果之前,不能进行其他操作。这就是第一次递归。

2) 调用 factorial(4) 时,实参为 4,形参 n 也为 4,不等于 0 或 1,会继续执行factorial(n-1) * n,也即执行factorial(3) * 4。为了求得这个表达式的结果,又必须先调用 factorial(3)。这就是第二次递归。

3) 以此类推,进行四次递归调用后,实参的值为 1,会调用 factorial(1)。此时能够直接得到常量 1 的值,并把结果 return,就不需要再次调用 factorial() 函数了,递归就结束了。

下表列出了逐层进入的过程

层次/层数

实参/形参

调用形式

需要计算的表达式

需要等待的结果

1

n=5

factorial(5)

factorial(4) * 5

factorial(4) 的结果

2

n=4

factorial(4)

factorial(3) * 4

factorial(3) 的结果

3

n=3

factorial(3)

factorial(2) * 3

factorial(2) 的结果

4

n=2

factorial(2)

factorial(1) * 2

factorial(1) 的结果

5

n=1

factorial(1)

1

递归的退出

当递归进入到最内层的时候,递归就结束了,就开始逐层退出了,也就是逐层执行 return 语句。

1) n 的值为 1 时达到最内层,此时 return 出去的结果为 1,也即 factorial(1) 的调用结果为 1。

2) 有了 factorial(1) 的结果,就可以返回上一层计算factorial(1) * 2的值了。此时得到的值为 2,return 出去的结果也为 2,也即 factorial(2) 的调用结果为 2。

3) 以此类推,当得到 factorial(4) 的调用结果后,就可以返回最顶层。经计算,factorial(4) 的结果为 24,那么表达式factorial(4) * 5的结果为 120,此时 return 得到的结果也为 120,也即 factorial(5) 的调用结果为 120,这样就得到了 5! 的值。

下表列出了逐层退出的过程

层次/层数

调用形式

需要计算的表达式

从内层递归得到的结果

(内层函数的返回值)

表达式的值

(当次调用的结果)

5

factorial(1)

1

1

4

factorial(2)

factorial(1) * 2

factorial(1) 的返回值,也就是 1

2

3

factorial(3)

factorial(2) * 3

factorial(2) 的返回值,也就是 2

6

2

factorial(4)

factorial(3) * 4

factorial(3) 的返回值,也就是 6

24

1

factorial(5)

factorial(4) * 5

factorial(4) 的返回值,也就是 24

120

至此,我们已经对递归函数 factorial() 的进入和退出流程做了深入的讲解,把看似复杂的调用细节逐一呈献给大家,即使你是初学者,相信你也能解开谜团。

递归的条件

每一个递归函数都应该只进行有限次的递归调用,否则它就会进入死胡同,永远也不能退出了,这样的程序是没有意义的。

要想让递归函数逐层进入再逐层退出,需要解决两个方面的问题:

  • 存在限制条件,当符合这个条件时递归便不再继续。对于 factorial(),当形参 n 等于 0 或 1 时,递归就结束了。

  • 每次递归调用之后越来越接近这个限制条件。对于 factorial(),每次递归调用的实参为 n - 1,这会使得形参 n 的值逐渐减小,越来越趋近于 1 或 0。

更多关于递归函数的内容

factorial() 是最简单的一种递归形式——尾递归,也就是递归调用位于函数体的结尾处。除了尾递归,还有更加烧脑的两种递归形式,分别是中间递归和多层递归:

  • 中间递归:发生递归调用的位置在函数体的中间;

  • 多层递归:在一个函数里面多次调用自己。

递归函数也只是一种解决问题的技巧,它和其它技巧一样,也存在某些缺陷,具体来说就是:递归函数的时间开销和内存开销都非常大,极端情况下会导致程序崩溃。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/184783.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

css背景

1、背景颜色&#xff1a;半透明 <style>div{width: 1000px;height: 100px;/* 背景颜色半透明&#xff0c;其他文字不受影响 */background: rgba(0 ,0 ,0 ,0.3 );}</style> </head> <body><div></div> </body>2、背景图 属性名: ba…

vue前端框架课程笔记(一)

目录初识Vue演示代码模板语法插值语法指令语法使用举例数据绑定两种数据绑定方式示例el和data的两种写法el的两种写法data的两种写法MVVM模型数据代理Object.defineProperty示例参数说明关于getter和setter使用举例泛化的数据代理举例vue中的数据代理原理事件处理指令methods配…

word样式管理:如何对样式进行修改删除

在前面的图文中简单为大家介绍了Word文本样式和表格样式的创建技巧。但对于已经创建好的样式&#xff0c;有时会对样式中的格式进行再次修改&#xff1b;或者是当拿到某个Word文档&#xff0c;它的样式经历多次或多人不断修改&#xff0c;可能导致样式库中的样式混乱不堪&#…

Dockerfile构建Tomcat镜像

Dockerfile构建Tomcat镜像构建步骤1 编写Dockfile文件2 dockcer build构建镜像3 docker run运行容器4 使用容器卷挂载搜索镜像的个数 docker search tomcat |wc -l因此&#xff0c;需要根据自己的项目需求来针对性的构建镜像 构建步骤 1 编写Dockfile文件 看成在编写一个纯净…

React 项目 黑马极客园

React 项目 黑马极客园git地址视频地址项目准备1.项目介绍2.项目搭建3.使用scss预处理器4.配置基础路由5.组件库antd使用6.配置别名路径8.别名路径提示9.安装dev-tools调试工具登录模块1.基本结构搭建2. 创建表单结构3. 表单校验实现4. 获取登录表单数据5. 封装http工具模块6. …

Android Studio Electric Eel | 2022.1.1 版本

前言 各位读者&#xff0c;新年快乐&#xff0c;现在是2023年了&#xff0c;新的一年&#xff0c;我们的开发也会焕然一新&#xff0c;Android开发的工具Android Studio&#xff0c;也能更新到Android Studio Electric Eel | 2022.1.1 版本了&#xff0c;短期内我将使用此版本学…

Delphi 中.deployproj文件结构

Delphi中&#xff0c;如果生成Android或者IOS等APP&#xff0c;需要在Project -> Deployment中按下Deploy图标 &#xff0c;然后就会生成和项目工程文件名称一致&#xff0c;后缀是.deployproj的文件。当然如果直接按下运行图标(RUN)也会自动生成这个文件。一、.deployproj文…

【自然语言处理】情感分析(五):基于 BERT 实现

情感分析&#xff08;五&#xff09;&#xff1a;基于 BERT 实现本文是 情感分析 系列的第 555 篇&#xff0c;也是本系列的收官之作。前四篇分别是&#xff1a; 【自然语言处理】情感分析&#xff08;一&#xff09;&#xff1a;基于 NLTK 的 Naive Bayes 实现【自然语言处理…

简答说明通用智能基础模型的基本处理逻辑

当能量多的时候 激发的是欲望 按照中庸之道 多余的能力要消耗掉 当没有可以查询的模仿行为或者是大量消耗能量行为的时候 就开始记录行为统计为一个发生概率行为表 当拥有了概率记录数据后&#xff0c;按照最大发生概率依次模仿行为 行为得到的反馈 反馈的时间越短 则判断剩余能…

【论文速递】BEVFormer: 通过时空变换器从多相机图像中学习BEV表示

【论文原文】&#xff1a;ECCV2022 - BEVFormer: Learning Bird’s-Eye-View Representation from Multi-Camera Images via Spatiotemporal Transformers 论文&#xff1a;https://arxiv.org/abs/2203.17270 代码&#xff1a;https://github.com/fundamentalvision/BEVFormer…

C++ opencv之配置环境

opencv下载官网下载连接:https://opencv.org/releases/选择相应版本下载&#xff0c;windows操作系统下载windows版本下载exe后&#xff0c;双击即可安装&#xff0c;选择好路径&#xff0c;尽量安装路径不要存在中文&#xff0c;安装好如下:vs2022配置opencv为DLL添加Path环境…

windows10搭建spark本地开发环境

windows10搭建spark本地开发环境1. spark概述2. 安装spark2.1 Windows10 安装Spark本地开发环境2.1.1 **版本说明**2.1.2 **环境准备**2.1.2.1 JDK 安装和配置2.1.2.1.1 JDK下载2.1.2.1.2 JDK安装2.1.2.1.3 JDK配置2.1.2.2 Scala 安装和配置2.1.2.2.1Scala下载2.1.2.2.2 Scala安…

51单片机学习笔记-11 DS18B02温度传感器(单总线)

11 DS18B02温度传感器 [toc] 注&#xff1a;笔记主要参考B站江科大自化协教学视频“51单片机入门教程-2020版 程序全程纯手打 从零开始入门”。 11.1 温度传感器与单总线通信 11.1.1 DS18B20温度传感器 DS18B20是一种常见的数字温度传感器&#xff0c;其控制命令和数据都是以…

SAP ADM100-Unit3 系统配置介绍:系统如何评估它的参数

本节将了解系统评估配置文件参数的顺序,并了解这些参数存储的位置。 1、配置profile参数 各个实例和SAP系统都是使用Profile配置文件参数来配置的。这些参数的默认值被定义在内核程序代码中。 可以通过配置文件改变这些参数的默认值,当实例被开启时将读取配置文件中参数值。…

大屏加载速度优化--突破chrome 6个请求线程限制

1. 问题 当大屏中的内容很多时&#xff0c;比如50个以上&#xff0c;整个页面呈现速度会慢很多&#xff0c;影响用户体验。 通过 chrome开发者工具可以看到&#xff0c;默认情况下&#xff0c;chrome仅开启6个请求线程&#xff0c;用于发起ajax请求。 2. 解决方案 改进的方式…

epoll模型要点总结

(图是网上的&#xff0c;懒得自己画了) 1 epoll_ctl是向红黑树rbr插入、删除、修改fd。epoll_wait在双向链表rdllist中查询IO可读、可写、错误事件。 为什么使用红黑树&#xff1f;从插入、删除考虑。 2 epoll_ctl插入新fd时&#xff0c;新建epitem&#xff0c;会设置回调函…

2023年第五届清洁能源与智能电网国际会议(CCESG 2023)

2023年第五届清洁能源与智能电网国际会议&#xff08;CCESG 2023&#xff09; 重要信息 会议网址&#xff1a;www.ccesg.org 会议时间&#xff1a;2023年4月21-23日 召开地点&#xff1a;广西-南宁 截稿时间&#xff1a;2023年2月28日 录用通知&#xff1a;投稿后2周内 收…

结合代谢组学和网络药理学研究康复消炎栓治疗慢性盆腔炎作用机制

文章标题&#xff1a;Integrated Metabolomics and Network Pharmacology Study on the Mechanism of Kangfuxiaoyan Suppository for Treating Chronic Pelvic Inflflammatory Disease 发表期刊&#xff1a;Frontiers in Pharmacology 影响因子&#xff1a;5.988 发表年份&…

读书:《好奇心:保持对未知世界永不停息的热情》

刚看到《好奇心》这本书的书名&#xff0c;我对《好奇心》还是有点好奇心的。 为什么小孩的好奇心比大人多&#xff1f;也不一定&#xff0c;如果家长或老师没有足够好的引导的话&#xff0c;孩子也会对周围的世界没有兴趣。 好奇心为两种&#xff1a;消遣性好奇、认识性好奇…

【go-zero】在微服务架构中是否要使用分布式事务 如何避免分布式的耦合 微服务与分布式事务的对立

微服务要不要引入分布式事务讨论问题&#xff1a;微服务要不要引入分布式事务&#xff1f;1、分布式事务的场景分析2、分析利与弊3、如何优化分布式事务3.1 什么是CAP理论3.2 方式一&#xff1a;避免使用分布式事务1&#xff09;同步阻塞2&#xff09;异步调用3&#xff09;粗粒…