【C语言】函数递归详解(二)

前言

        在上一篇博客函数递归详解(一)中讲解了什么是递归,递归的思想及限制条件以及两个递归的例子,这一篇博客将讲解递归与迭代的关系。

递归与迭代

递归是一种很好的编程技巧,但是同很多技巧一样也是可能被误用的,就像函数递归详解(一)中的举例1一样,看到推导公式就很容易写出地递归形式的代码:

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

Fcat函数是可以产生正确的结果,但是在递归调用的过程中设计一些运行的开销 。

在C语言中每一次函数调用,都要需要为本次函数调用在栈区申请一块内存空间来保存 函数调用期间的各种局部变量的值,这块空间被称为运行时堆栈,或者函数栈帧
函数不返回,函数对应的栈帧空间就一直占用, 所以如果函数调用中存在递归调用的话,每一次递归函数调用都会开辟属于自己的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间。
所以如果采用函数递归的方式完成代码,递归层次太深,就会浪费太多的栈帧空间,也可能引起栈溢出(stack overflow)的问题。
所以如果不想使用递归就得想其他的办法,通常就是迭代的方式(通常就是循环的方式) .

 比如:计算n的阶乘,也是可以使用迭代的方式进行解决,并且效率比递归更高。

int Fact(int n)
{
	int i = 0;
	int ret = 1;
	for(i=1;i<=n;i++)
	{
		ret *= i;
	}
	return ret;
}

事实上,我们看到的许多问题都是以递归的形式进行解释的,只是因为它比非递归形式更加清晰,但是这些问题的迭代实现往往比递归实现效率更高

但是当一个问题非常复杂,难以用迭代的方式实现时,此时递归的简洁性便可以补偿它所带来的开销。

举例3:求第n个斐波那契数列 

我们也能举出更加极端的例子,就像计算第n个斐波那契数,是不适合用递归求解的,但是斐波那契数的问题也是可以通过使用递归的形式描述的,如下:

 看到上述公式,很容易诱导我们将代码写为递归的形式,如下:

int Fib(int n)
{
	if(n<=2)
	
		return 1;
	
	else
		return Fib(n - 1) + Fib(n - 2);
}

 测试代码:

int Fib(int n)
{
	if(n<=2)
	
		return 1;
	
	else
		return Fib(n - 1) + Fib(n - 2);
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret=Fib(n);
	printf(" %d\n", ret);
	return 0;
}

🔺当我们n输入50的时候,需要很长的时间才能算出结果,或者根本算不出结果,这个计算所耗费的时间是我们很难接受的,这也说明递归的写法是非常低效的,那是为什么呢 ?我们看下面这个递归示意图:

其实递归程序会不断的展开,在展开的过程中,我们很容易就能发现,在递归中有重复计算,而且递归层次越深,冗余计算就会越多,我们可以做一个测试

测试代码:

int count = 0;
int Fib(int n)
{	
	if (n == 3)
		count++;
	if(n<=2)
	
		return 1;
	
	else
		return Fib(n - 1) + Fib(n - 2);
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret=Fib(n);
	printf(" %d\n", ret);
	printf("在递归过程中总共计算了%d次\n", count);
	return 0;
}

我们定义一个全局变量count,当计算到第3个斐波那契数的时候我们让count++,运行程序计算第40个斐波那契数,我们看一下第3个斐波那契数重复计算了多少次 。

结果如下:

当我们计算第40个斐波那契数的时候,过程中仅仅第3个斐波那契数就被重复计算了39088169次,足以看出递归过程中的开销有多么巨大。

那么我们知道斐波那契数的前两个都是1,前两个相加便是第三个数,那么我们从前往后从大到小计算就可以了,于是便有如下的迭代代码:

int Fib(int n)
{
	int a = 1;
	int b = 1;
	int c = 1;
	while(n>=3)
	{
		c = a + b;
		a = b;
		b = c;
	}
	return c;
}

用迭代的方式区实现这个代码,效率高出很多。

有时候递归虽好,但是也会引出一些问题,所以一定不要迷恋递归,适可而止就好。

递归和迭代的选择:

1.如果使用递归写代码,非常容易,写出的代码没问题,那就可以使用递归解决。

2.如果使用递归写出的代码缺陷非常明显,那就不能使用递归,考虑使用迭代解决问题。

 以上便是我为大家带来的函数递归的第二部分内容,若有不足,望各位大佬在评论区指出,谢谢大家!可以留下你们点赞、收藏和关注,这是对我极大的鼓励,我也会更加努力创作更优质的作品。再次感谢大家!

 

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

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

相关文章

深入剖析Java Web开发中的过滤器、拦截器和AOP

文章目录 1. 过滤器&#xff08;Filter&#xff09;1.1 过滤器的概念1.2 过滤器的应用场景1.3 过滤器的示例代码 2. 拦截器&#xff08;Interceptor&#xff09;2.1 拦截器的概念2.2 拦截器的应用场景2.3 拦截器的示例代码 3. AOP&#xff08;面向切面编程&#xff09;3.1 AOP的…

如何选择一款安全可靠的跨网安全数据交换系统?

随着网络和数据安全的重视程度增加&#xff0c;为了有效地保护内部的核心数据资产&#xff0c;普遍会采用内外网隔离的策略。像国内的政府机构、金融、能源电力、航空航天、医院等关乎国计民生的行业和领域均已进行了网络的隔离&#xff0c;将内部划分成不同的网段&#xff0c;…

基于AWS Serverless的Glue服务进行ETL(提取、转换和加载)数据分析(二)——数据清洗、转换

2 数据清洗、转换 此实验使用S3作为数据源 ETL: E extract 输入 T transform 转换 L load 输出 大纲 2 数据清洗、转换2.1 架构图2.2 数据清洗2.3 编辑脚本2.3.1 连接数据源&#xff08;s3&#xff09;2.3.2. 数据结构转换2.3.2 数据结构拆分…

CSS-200个小案例(一)

文章目录 1.Simple Parallax Scrolling Effect&#xff08;简单的视差滚动效果&#xff09;2.Fullscreen Video Background&#xff08;全屏视频背景&#xff09;3.Transform Effects on Scroll(滚动时产生的变换效果&#xff09;4.Fullscreen Overlay Responsive Navigation M…

今日实施|解读新国标对数据库审计的能力要求

数据库审计是数据安全建设不可或缺的技术工具之一&#xff0c;无论是国家级的法律或标准&#xff0c;还是等保以及行业级的安全标准均对使用数据库审计有明确要求。据相关数据统计显示&#xff0c;数据库审计产品的市场需求已占据中国数据库安全市场容量的6成以上。 12月1日&am…

身份统一管理创新与优化 ——华为云OneAccess应用身份管理服务的2023年

2023年&#xff0c;随着云计算、物联网、人工智能等技术的快速发展&#xff0c;企业面临着数字化转型的巨大挑战与机遇。身份统一管理是企业数字化转型的基础&#xff0c;也是业务发展的关键。如何高效、安全、灵活地实现身份统一管理&#xff0c;成为企业亟待解决的首要课题。…

如何将四元数转换为旋转矩阵

什么是四元数&#xff1f; 四元数是表示物体在三维空间中的方向和旋转的几种数学方法之一。另一种方法是使用基于欧拉角的旋转矩阵&#xff0c;即滚动、俯仰和偏航&#xff0c;就像的封面图片。 通常使用四元数代替欧拉角旋转矩阵&#xff0c;因为“与 旋转矩阵相比 &#xff…

使用Python Flask搭建Web问答应用程序并发布到公网远程访问

使用Python Flask搭建web问答应用程序框架&#xff0c;并发布到公网上访问 文章目录 使用Python Flask搭建web问答应用程序框架&#xff0c;并发布到公网上访问前言1. 安装部署Flask并制作SayHello问答界面2. 安装Cpolar内网穿透3. 配置Flask的问答界面公网访问地址4. 公网远程…

数字化时代的保镖:实人认证API在身份验证中的角色

前言 随着数字化时代的迅猛发展&#xff0c;个人信息的安全性和隐私保护成为了当今社会中备受关注的话题。在这个背景下&#xff0c;实人认证API崭露头角&#xff0c;成为数字领域中的一项重要技术&#xff0c;为身份验证提供了全新的保障机制。本文将探讨实人认证API在身份验…

实现用户登陆

输入用户名和密码&#xff0c;如果输入用户名和密码正确&#xff0c;允许登录 编程过程中采用字符串拉接。 SQL注入&#xff0c;当使用拼接的sql语句. 输入密码时把语句拼接成or&#xff0c;or后面跟上一个条件正确的式子。 Java 防止sql注入&#xff0c;预编译手段&#xff…

网上下载的pdf文件,为什么不能复制文字?

不知道大家有没有到过这种情况&#xff1f;在网上下载的PDF文件打开之后&#xff0c;发现选中文字之后无法复制。甚至其他功能也都无法使用&#xff0c;这是怎么回事&#xff1f;该怎么办&#xff1f; 当我们发现文件打开之后&#xff0c;编辑功能无法使用&#xff0c;很可能是…

【教3妹学编程-算法题】到达首都的最少油耗

3妹&#xff1a;“太阳当空照&#xff0c;花儿对我笑&#xff0c;小鸟说早早早&#xff0c;你为什么背上炸药包” 2哥 :3妹&#xff0c;什么事呀这么开发。 3妹&#xff1a;2哥你看今天的天气多好啊&#xff0c;阳光明媚、万里无云、秋高气爽&#xff0c;适合秋游。 2哥&#x…

距离传感器VL6180V1NR/1

参考模块 【优信电子】VL6180X近距离感测器 环境光线传感器 手势识别-淘宝网 (taobao.com)https://item.taobao.com/item.htm?spma21n57.1.0.0.13f7523csXwKYp&id584789574087&ns1&abbucket6#detail检测原理 系统框图 价格参考 电路连接 怎样快速生成距离传感器曲…

STM32上模拟CH340芯片的功能 (一)

#虚拟串口模拟CH340# 后续代码更新放gitee 上 一、思路 1. 确定通信接口&#xff1a;CH340是一款USB转串口芯片&#xff0c;因此您需要选择STM32上的某个USB接口来实现USB通信。通常情况下&#xff0c;STM32系列芯片都有内置的USB接口&#xff0c;您可以根据您的具体型号选择…

数据库——索引的数据结构

在数据库中引入索引可以提高查询速率&#xff0c;那么为什么引入索引可以提高查询速率呢&#xff0c;其底层组织数据的数据结构又是什么呢&#xff1f;接下来&#xff0c;一起来探讨索引的数据结构吧&#xff01;&#xff01;&#xff01; 在介绍数据库索引数据库前&#xff0…

适用于 Windows 的最佳(免费/付费)数据恢复软件

借助最佳数据恢复工具从 Windows PC 恢复丢失和删除的数据 您是否正在寻找一种巧妙的方法来从计算机中取消删除或恢复已删除的文件&#xff1f;如果是&#xff0c;那么这篇文章就是为您准备的&#xff01;在本教程中&#xff0c;我们整理了一份全面的数据恢复软件列表&#xf…

[BJDCTF2020]ZJCTF,不过如此1

提示 伪协议的各种应用 首先我们来一步一步分析 首先要判断text是否传入参数&#xff0c;并且将传入的text以只读的方式打开要绝对等于I have a dream才会进入下一步 这里需要用到伪协议data://text/plain或者php://input都可以 最终要利用到这个include包含函数 这里提示了…

论文解读:Axial-DeepLab: Stand-Alone Axial-Attention forPanoptic Segmentation

论文是一个分割任务&#xff0c;但这里的方法不局限于分割&#xff0c;运用到检测、分类都可以。 论文下载 https://www.yuque.com/yuqueyonghupjh9oc/ovceh4/onilw42ux6e9n1ne?singleDoc# 《轴注意力机制》 一个问题 为什么transformer一开始都有CNN&#xff1a;降低H、W…

Open3D 最小二乘拟合空间直线(方法二)

目录 一、算法原理1、算法过程2、参考文献二、代码实现三、结果展示四、相关链接本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理

分享70个节日PPT,总有一款适合您

分享70个节日PPT&#xff0c;总有一款适合您 70个节日PPT下载链接&#xff1a;https://pan.baidu.com/s/1IRIKuFoGjQJ14OVkeW_mDQ?pwd6666 提取码&#xff1a;6666 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易…