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

前言

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

递归与迭代

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

int Fact(int n)
{if (n == 0)return 1;elsereturn 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;elsereturn Fib(n - 1) + Fib(n - 2);
}

 测试代码:

int Fib(int n)
{if(n<=2)return 1;elsereturn 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;elsereturn 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.如果使用递归写出的代码缺陷非常明显,那就不能使用递归,考虑使用迭代解决问题。

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

 

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

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

相关文章

Centos7 制作Openssh9.5 RPM包

Centos7 制作Openssh9.5 RPM包 最近都在升级Openssh版本到9.3.在博客里也放了openssh 9.5的rpm包. 详见:https://blog.csdn.net/qq_29974229/article/details/133878576 但还是有小伙伴不停追问这个rpm包是怎么做的,怕下载别人的rpm包里被加了盐. 于是做了个关于怎么用官方的o…

yolov5实现多图形识别和图像训练

1.使用了yolov7,检测更好,但是训练上有问题,运行不起来,转了一圈发现yolov5是应用更广泛使用简单 2.怎么使用 //下载代码 https://github.com/ultralytics/yolov5 //安装依赖 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple some-package //按…

CMake中的CACHE关键字

2023年12月5日&#xff0c;周二晚上 在 CMake 中&#xff0c;CACHE 关键字用于在变量定义时将其值缓存起来&#xff0c;以便在后续的 CMake 运行中重用。这对于在多次构建过程中保持变量的持久性和一致性非常有用。 当使用 CACHE 关键字定义一个变量时&#xff0c;CMake 将会为…

【Axure高保真原型】3D大屏可视化模板

今天和大家分享3D大屏可视化的原型模板&#xff0c;里面包括3D条形图、3D柱状图、3D饼图、3D环形图、3D金字塔图&#xff0c;鼠标移入图表&#xff0c;对应区域会高亮变色&#xff0c;并且显示对应的数据标签&#xff0c;具体效果可以点击下方视频观看或打开下方预览地址查看哦…

【PduR路由】PduR模块详细介绍

目录 1.PDUR模块功能介绍 2.关键概念理解 3.功能详细设计 3.1I-PDU handling 3.1.1 I-PDU Reception to upper module(s) 3.1.1.1 Communication Interface 3.1.1.2 Transport Protocol 3.1.2 I-PDU Transmission from upper module(s) 3.1.2.1 Multicast 3.1.2.2 Co…

LeetCode 2477. 到达首都的最少油耗:深度优先搜索(DFS)

【LetMeFly】2477.到达首都的最少油耗&#xff1a;深度优先搜索(DFS) 力扣题目链接&#xff1a;https://leetcode.cn/problems/minimum-fuel-cost-to-report-to-the-capital/ 给你一棵 n 个节点的树&#xff08;一个无向、连通、无环图&#xff09;&#xff0c;每个节点表示一…

仓库管理系统【GUI/Swing+MySQL】(Java课设)

系统类型 Swing窗口类型Mysql数据库存储数据 使用范围 适合作为Java课设&#xff01;&#xff01;&#xff01; 部署环境 jdk1.8Mysql8.0Idea或eclipsejdbc 运行效果 本系统源码地址&#xff1a; 更多系统资源库地址&#xff1a;更多Java课设系统 更多系统运行效果展示…

JavaSE基础50题:5. 求两个正整数的最大公约数

方法 我们用到辗转相除法&#xff0c;也叫欧几里得算法。 如&#xff1a;求 32和26 的最大公约数。 32➗ 26 1……6 &#xff08;此时余数不为0&#xff0c;继续&#xff0c;此行的除数26作为下一行的被除数&#xff0c;余数6作为下一行的除数&#xff09; 26 ➗ 6 4……2&a…

为什么Nginx被称为反向代理

下图显示了 &#x1d41f;&#x1d428;&#x1d42b;&#x1d430;&#x1d41a;&#x1d42b;&#x1d41d; &#x1d429;&#x1d42b;&#x1d428;&#x1d431;&#x1d432; 和 &#x1d42b;&#x1d41e;&#x1d42f;&#x1d41e;&#x1d42b;&#x1d42c;&#…

甘草书店:#7 2023年11月19日 星期日 波澜不惊的日子里稳步前行

前进&#xff0c;可以伴着惊涛骇浪&#xff0c;也可以波澜不惊。 几番沟通&#xff0c;多方协商之后&#xff0c;甘草书店硬装方案基本确定&#xff0c;近期开始施工。 书目选择方面也在逐步推进。 就像之前设想的&#xff0c;划分成企业经管和个人成长两大类的前提下&#…

SpringBoot3-创建自定义启动器,使用自定义starter启动器

1、创建自定义启动工程pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.a…

软件设计之适配器模式

类模式 我们知道插座的电压为交流电220V&#xff0c;而日常电器使用的是直流电且电压会较小&#xff0c;比如手机充电会通过插头适配器达到额定的输入电流。下面我们实现这个案例&#xff1a;将220V电压转化为5V的电压。 package Adapter.Class;public class Adapter extends …

算法通关村——数论问题

数论是一个很重要的学科&#xff0c;覆盖领域极广&#xff0c;小到小学的智力问题&#xff0c;大到世界顶级科学家都一直在研究相关问题&#xff0c;因此其难度跨度非常大。在程序设计里 &#xff0c;也经常会出现数论的问题&#xff0c;但是&#xff0c;这些一般都是比较基本的…

【@ConfigurationProperties注解的用处】

介绍 ConfigurationProperties 是 Spring 框架中的一个注解&#xff0c;用于将配置文件中的属性映射到 Java 对象的字段上。它的主要用途是简化配置文件与 Java 对象之间的映射过程&#xff0c;使得配置更加方便、可读&#xff0c;并提供类型安全的属性访问。 用途和特性 属性…

vmware ubuntu22 访问github

1.虚拟机选NAT模式。 2.firefox找到下图setting。 3.选第四个&#xff0c;填主机ip和局域网代理的端口号。 4. 此时你应该能访问github了。

vue+ts实现离线高德地图 内网离线高德地图

1、下载瓦片 我是用最简单的软件下载——MapDownloader 链接&#xff1a;https://pan.baidu.com/s/1Hz__HcA5QhtGmjLNezC_pQ 提取码&#xff1a;6lek 来源&#xff1a;https://blog.csdn.net/fuhanghang/article/details/131330034 2、部署私有化瓦片资源 这里也是用最简单的…

顺序表和链表面试题

文章目录 顺序表(1)原地移除数组中所有的元素val&#xff0c;要求时间复杂度为O(N)&#xff0c;空间复杂度为O(1)。(2)删除有序数组中的重复项(3)合并两个有序数组 链表(1)删除链表中等于给定值 val 的所有节点(2)反转一个单链表(3) 合并两个有序链表(4)链表的中间结点(5)链表中…

顶级资源!五个免费图标素材网站

图片太花哨了&#xff0c;纯文本太单调了&#xff1f;别忘了设计师的魔法武器——图标&#xff01;图标材料是UI设计师不可缺少的一部分。优秀的图标设计不仅可以提高界面美感&#xff0c;还可以提高用户的互动体验&#xff0c;帮助用户更好地了解应用程序的功能和信息。在本文…

动态类型语言与静态类型语言的对比与比较

编程语言可以根据类型系统和类型检查时机分为动态编程语言和静态编程语言两大类&#xff0c;它们在运行时的代码检查方式、变量类型的使用方式等方面有很大的区别。这一块你知道吗&#xff1f; 本文将为您详细讲解两种编程语言的优缺点&#xff0c;以及它们的应用场景。 动态编…

Innodb-ruby深入探索Innodb存储结构

达在之前已经分享过Innodb数据存储结构知识&#xff0c;但是都是基于理论原理知识理解&#xff0c;今天利用Innodb文件解析工具ruby进行探索Innodb真实的存储结构。 索引原理过程&#xff1a;【Mysql】 InnoDB引擎深入 - 数据页 | 聚集索引_innodb的聚集索引的数据插入_Surviv…