C语言(递归)

                        Hi~!这里是奋斗的小羊,很荣幸各位能阅读我的文章,诚请评论指点,关注+收藏,欢迎欢迎~~     

                        💥个人主页:小羊在奋斗

                        💥所属专栏:C语言   

        本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为同样是初学者的学友展示一些我的学习过程及心得。文笔、排版拙劣,望见谅。

                               一、递归

                                        1、什么是递归

                                        2、递归的限制条件

                                        3、递归的举例

                                        4、递归与迭代

1、什么是递归

        递归是C语言学习绕不开的一个话题,那什么是递归呢?递归其实是一种解决问题的方法,在C语言中,递归就是函数自己调用自己。若一个复杂的问题,能层层分解为若干个相对简单且与原问题相似的子问题,则原问题可以采用递归算法求解,所以递归的思想就是把大事化小的过程。

        递归中的递是递推的意思,归是回归的意思。

        来看一个简单的递归示例:

        但是上述代码会陷入死递归,因为递归需要一个限制条件, 不然会一直向内存申请空间但不释放,导致栈溢出(Stack overflow)VS调试技巧中也提到过栈溢出,但这里也不细说,因为内容太多,后面会有专门的文章。

2、递归的限制条件

        递归在书写的时候,有2个必要的限制条件:

        (1)递归存在限制条件,也就是出口,当满足这个限制条件的时候,递归不再继续;

        (2)每次递归调用后越来越接近这个限制条件。

        这么说可能有些生硬,不过在看完了这篇文章后相信你会对这两句话有所体会。

3、递归的举例

        3.1求n的阶乘(不考虑溢出)

        我们知道,0和1的阶乘为1,n的阶乘是所有小于及等于n的正整数的积。

        比如:4!= 4*3*2*1,  3!= 3*2*1, 那么4!= 4*3!,即n!= n(n - 1)!。这样的思路就是把一个较大的问题,转换为一个与原问题相似,但规模较小的问题来解决。当n一直减到n = 1的时候,n的阶乘为1,这是我们本来就知道的。到这里,我们就得到了求n的阶乘的公式:

        函数实现如下:

#include <stdio.h>

int fact(int x)
{
	if (0 == x || 1 == x)
	{
		return 1;
	}
	else
	{
		return x * fact(x - 1);
	}
}

int main()
{
	int n = 0;
	scanf("%d", &n);
	int m = fact(n);
	printf("%d\n", m);
	return 0;
}

         运行结果(这里不考虑n太大的情况,会溢出):

        图形演示:

         3.2输入一个整数顺序打印每一位

        我们拿到这个题目后,很容易想到把这个数的每一位单独拿出来再打印,但问题是,怎么拿到一个数的每一位呢?有一个熟知的方法就是通过模10(%10)和除10(/10)不断循环来取得一个数的每一位,但是这个办法取出来的是逆序的,我们这里需要的是顺序的,很明显我们常用的这个方法行不通。

        虽然这个方法行不通,但是它给了我们一个灵感,我们发现一个数的最低位是很容易得到的,因此我们可以这样想:如果想要按顺序打印1234的每一位,我们可以先打印123,再打印4;打印123之前先打印12,再打印3;打印12之前先打印1,再打印2。这样不就实现我们想要的效果了嘛。

        不难发现,上面解决问题的思路用递归很容易解决,既然有了思路,废话不多说,我们直接上代码演示:

#include <stdio.h>

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

int main()
{
	int n = 0;
	scanf("%d", &n);
	print(n);
	return 0;
}

        是不是看起来很简单,运行结果为:

        如果不太明白执行逻辑,不要慌,我直接上图细细演化每一步的执行过程:

4、递归与迭代

         递归是一种很好的编程技巧,但是和很多技巧一样,也是可能会被误用的。就像3.1一样,看到推导的公式,很容易就被写成递归的形式:

        Fact()函数是可以得出正确的结果,但是在函数递归的时候存在一些运行时的开销。

        在C语言中每一次函数调用,都需要为本次函数调用在栈区申请一块内存空间来保存函数调用期间的各种局部变量的值,这块空间被称为运行时栈帧,或者函数栈帧。只要函数不返回,函数对用的栈帧空间就一直被占用,所以如果函数调用中存在递归调用的话,每一次递归函数调用都会开辟属于自己的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间。

        所以如果采用函数递归的方式完成代码,递归层次太深,就会浪费太多的栈帧空间,也可能引起溢出。

        为了避免这些问题,就得想其他的办法,通常就是用迭代的方法来代替递归。我们学过的循环就是一种迭代。比如上面的计算n的阶乘问题,我们也可以用循环的方法来解决:

        很明显,虽然递归的思想更容易理解,但是循环的方法更加简洁,也更加高效。

        事实上,我们看到的很多问题都是以递归的形式进行解释的,这只是因为它比非递归的形式更加清晰,但是这些问题的迭代实现往往比递归实现效率高。当一个问题非常复杂,难以使用迭代的方式实现时,递归实现的简洁性就弥补了它所带来时的运行时开销。

        例如:求第n个斐波那契数

        这个问题是不适合使用递归来求解的,但是斐波那契数的问题通常是用递归的形式来解释的:

        看到这个公式,我们很容易写出递归函数:

 

        看似我们用递归很容易的就解决了这个问题,但当我们输入较大的数时,程序运行的过程就会很费劲,比如我们输入50:

 

        可以看到程序运行了半天还没得出结果。为什么呢?其实,我们上面写出的代码在输入较大的数时,会有大量的重复计算,代码执行的效率非常低。这个时候我们就应该换个办法解决,比如循环。 

        那我们用循环具体该怎么实现呢?想要求第n个斐波那契数,无非就是这第n个数的前两个数相加,上面递归的方法其实是逆着计算的,在循环中我们可以顺着计算。假设第一个和第二个数分别为a和b,让a和b相加,值赋给c,再将b的值赋给a,将c的值赋给b,循环执行,直到n的值不再大于2,退出循环。

        当我们求第50个斐波那契数时,也会很快的得出答案(只是结果是错的,因为超过了整型的范围,影响不大):

 

        所以说,递归虽好,但不宜迷恋,要根据实际问题选择合适的解决方法。 

                                       点击跳转主页—> 💥个人主页小羊在奋斗

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

win10安装.NET Framework 3.5(包括.net2.0和3.0)

打开控制面板 选择”程序” 点击”启用或关闭Windows功能“ 把.NET Framework 3.5选项勾选即可&#xff0c;若没有下载的&#xff0c;下载即可。 PS:如果下载过程出错&#xff0c;按如下流程&#xff1a; 右击”此电脑”选择“管理”&#xff0c;找到“服务和应用程序”&#x…

JAVA(三)常用类和API

目录 常用类与基础API---String String的内存结构 构造器和常用方法 字符串构建 String与其他结构间的转换 String的常用API 系列1&#xff1a;常用方法 系列2&#xff1a;查找 系列3&#xff1a;字符串截取 系列4&#xff1a;和字符/字符数组相关 系列5&#xff1a;开头…

Mac 解决外接移动硬盘(NTFS格式)无法写入的问题

文章目录 1. 问题描述2. 解决步骤 1. 问题描述 MacOS 可以识别 NTFS 格式的磁盘&#xff0c;但是默认情况下是只读模式&#xff0c;即无法向 NTFS 格式的磁盘写入数据。这是因为 NTFS 是 Windows 系统默认的文件系统格式&#xff0c;而 MacOS 对 NTFS 的写入支持是有限的。 如…

python软件开发遇到的坑-相对路径文件读写异常,不稳定

1. os.chdir()会影响那些使用相对路径读写文件的程序&#xff0c;使其变得不稳定&#xff0c;默认情况下&#xff0c;当前工作目录是主程序所在目录&#xff0c;使用os.chdir会将当前工作目录修改到其他路径。 资料&#xff1a; python相对路径写对了却报错是什么原因呢&#…

什么情况下 MySQL 连查询都能被阻塞?

MySQL 的锁也是不少&#xff0c;在哪种情况下会连查询都能被阻塞&#xff1f;这是一个有意思的问题。 工作中&#xff0c;很多开发和 DBA 可能接触较多的锁也就行锁了。对于行锁&#xff0c;阻塞写能理解&#xff0c;阻塞读实在是想不到。能阻塞读的那肯定是颗粒度更大的锁了&…

用于视频大型多模态模型(Video-LMMs)的复杂视频推理和鲁棒性评估套件

1 引言 最近,大型语言模型(LLMs)在同时处理广泛的NLP任务的同时展示了令人印象深刻的推理和规划能力。因此,将它们与视觉模态集成,特别是用于视频理解任务,催生了视频大型多模态模型(Video-LMMs)。这些模型充当视觉聊天机器人,接受文本和视频作为输入,并处理各种任务,包括视频…

技术分享 | 京东商品API接口|京东零售数据可视化平台产品实践与思考

导读 本次分享题目为京东零售数据可视化平台产品实践与思考。 主要包括以下四个部分&#xff1a; 1.京东API接口介绍 2. 平台产品能力介绍 3. 业务赋能案例分享 01 京东API接口介绍 02 平台产品能力介绍 1. 产品矩阵 数据可视化产品是一种利用数据分析和可视化技术&…

软件测试小妙招:详细解读 postman接口测试导入导出操作

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 postman中的集合脚本&#xff0c;环境变量、全局变量全部都可以导出&#xff0c;然后分享给团队…

618购物狂欢有哪些值得买的?五款心水好物真实分享!

618购物狂欢即将到来&#xff0c;你是不是已经迫不及待地期待着各种优惠和折扣&#xff1f;在这个充满购物狂欢的时刻&#xff0c;大家可能会犹豫在众多商品中该如何选择。不用担心&#xff01;我已经为大家精心挑选了五款心水好物&#xff0c;并进行了真实的分享&#xff0c;帮…

在家中访问一个网站的思考

在家中访问一个网站的思考 1、家庭网络简介2、家庭WLAN DHCP2.1、家庭路由器PPPOE拨号2.2、DHCP&#xff08;动态主机配置协议&#xff09;2.3、接入家庭网的主机IP地址2.4、家庭总线型以太网2.5、Mac地址2.6、ARP协议2.7、IP协议 & UDP/TCP协议2.8、NAT&#xff08;Netwo…

使用凌鲨建立软件研发技能学习小组

凌鲨(OpenLinkSaas)的团队功能除了提供论坛功能&#xff0c;还能记录团队成员的成长记录。 使用方法 打开团队功能 团队功能在默认情况下是关闭的&#xff0c;你可以在登录后打开团队功能开关。 创建学习团队 日报/周报/个人目标一般是企业团队需要&#xff0c;建议关闭。 …

FPGA第二篇,FPGA与CPU GPU APU DSP NPU TPU 之间的关系与区别

简介&#xff1a;首先&#xff0c;FPGA与CPU GPU APU NPU TPU DSP这些不同类型的处理器&#xff0c;可以被统称为"处理器"或者"加速器"。它们在计算机硬件系统中承担着核心的计算和处理任务&#xff0c;可以说是系统的"大脑"和"加速引擎&qu…

通过 Java 操作 redis -- set 集合基本命令

关于 redis set 集合类型的相关命令推荐看Redis - Set 集合 要想通过 Java 操作 redis&#xff0c;首先要连接上 redis 服务器&#xff0c;推荐看通过 Java 操作 redis -- 连接 redis 本博客只介绍了一小部分常用的命令&#xff0c;其他的命令根据上面推荐的博客也能很简单的使…

12大价值:揭秘可视化大屏在机械行业应用(大量案例图)

1. 生产监控&#xff1a; 可视化数据大屏可以实时显示机械自动化生产线的运行状态、生产进度、设备故障等信息&#xff0c;帮助管理人员及时了解生产情况并做出相应的决策。 2. 故障诊断&#xff1a; 通过可视化数据大屏&#xff0c;可以将机械自动化设备的故障信息以图表、…

低代码在物品领用领域数字化转型的案例分析

办公用品管理数字化不仅代表了企业管理模式的革新&#xff0c;更是提升运营效率和成本控制的关键举措。通过数字化手段&#xff0c;企业能够实现采购、库存、领用等流程的自动化和智能化管理&#xff0c;大幅减少人工操作&#xff0c;提高处理速度&#xff0c;确保数据的准确性…

Zabbix+Grafana-常见报错及异常处理方式记录

文章目录 Zabbix安装篇Zabbix Web页面连接数据库失败 Zabbix使用篇中文显示不全 Zabbix报警篇新建的用户&#xff0c;配置报警后&#xff0c;无法收到报警 Grafana安装篇Windows系统安装时&#xff0c;添加zabbix报错&#xff1a;An error occurred within the plugin Zabbix安…

STM32快速入门(串口传输之USART)

STM32快速入门&#xff08;串口传输之USART&#xff09; 前言 USART串口传输能实现信息在设备之间的点对点传输&#xff0c;支持单工、半双工、全全双工&#xff0c;一般是有三个引脚&#xff1a;TX、RX、SW_RX&#xff08;共地&#xff09;。不需要一根线来同步时钟。最大优…

【小迪安全2023】第61天:服务攻防-中间件安全CVE复现K8sDockeruettyWebsphere

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

不要和别人比,要和自己的过去比!才会有进步!

现在的人都喜欢拿自己去和别人比较&#xff0c;当然是和比你混得好的人比&#xff0c;比你弱的你也不会去比。比如这个朋友又换了一辆车&#xff0c;那个朋友又买了一套房&#xff0c;另一个朋友又加薪了等等&#xff0c;比来比去总觉得比不上别人。这样比较对自己很不好&#…

【C语言视角】数据结构之~二叉树

前言&#xff1a;总所周知~数据结构的二叉树对于初学者来说是一个十分难理解的知识点。接下来&#xff0c;请阅读本人对二叉树拙劣的理解~ 目录 1.二叉树概念及结构 和性质 二叉树的结构 二叉树的存储结构 2.二叉树顺序结构 3.二叉树链式结构的实现 二叉树层序遍历 1.二叉树…