函数递归和迭代

1.什么是递归?

在C语言中递归就是自己调用自己。

看一下简单函数的递归:

上面的代码实现演示一下函数的递归,最终是会陷入死循环的,栈溢出 。

1.1递归的思想:

把一个大型的问题一步一步的转换成一个个小的子问题来解决,直到子问题不能再被分解时,大事化小,就像剥洋葱一样。

1.2递归的限制条件

必须具备的两个条件:

  • 递归存在限制条件,当满足限制条件时,递归便不再继续。
  • 每次递归调用之后越来越越接近这个限制条件

2.递归的举例

2.1求 n 的阶乘

输入一个正整数并计算出该正整数的阶乘,规定 0!=1。

当输入的是0的话,则返回1

其余的按公式计算:Fact(n)=n*Fact(n-1),  n>0

//用递归来写计算 n!的结果
//5!=5*4*3*2*1 = 5*4!
//4!=  4*3*2*1 = 4*3!
//3!=    3*2*1 = 3*2!
//2!=      2*1 = 2*1!
//1!=        1 = 1*0!
//0!=        1int Fact(int i)
{if (i == 0)return 1;elsereturn Fact(i - 1) * i;}int main()
{int n = 0;scanf("%d", &n);int ret=Fact(n);printf("%d\n", ret);return 0;
}

n 太大的话就会出现溢出的问题 。

2.2输入一个整数,按照顺序输出 

例如:输入:1234
           输出:1 2 3 4

 拆分过程:

  • 1234  拆分为:打印 123 + 打印 4

重新赋值为:123

  • 123   拆分为:打印 12    + 打印 3

重新赋值:    12

  • 12     拆分为:打印 1      + 打印  2

打印:            1

重新赋值:n=n/10;

打印       :n%10; 

这样的话我们就可以实现先打印 1—>2—>3—>4 

//输入一个整数,按照顺序输出 ——递归
//例如:输入:1234
//      输出:1 2 3 4void Print(int n)
{if (n > 9){Print(n / 10);}printf("%d ",n%10);
}int main() 
{int num = 0;scanf("%d", &num);Print(num);return 0;
}

 

3.递归与迭代

递归是一种很好的编程技巧,它要求程序员的技巧性更高,但是也可能会被误用,如前面的阶乘的例子,看见推导出的公式,很容易就写成递归形式:

int Fact(int i)
{if (i == 0)return 1;elsereturn Fact(i - 1) * i;}

死递归函数调用好多次后会导致栈溢出,但是里面并没有创建任何的变量,这是为什么呢?

这是因为有时即使函数里面没有任何的变量,但是每次的函数调用都会向内存栈区上申请一块空间,这一块空间主要用来存放函数中的局部变量和函数调用过程中的上下文的信息。这一块空间一般叫做:函数的运行时堆栈,也叫函数栈帧空间。编译会根据需要来进行开辟空间。

函数不返回,函数对应的栈帧空间就一种被占用着,所以如果函数调用中存在递归函数的话,每一次的递归函数调用都会开辟属于自己的栈帧空间,知道函数递归不再继续,开始回归,才逐层的释放栈帧空间。

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

如果不使用递归的话,通常就是用迭代的方式(一般为循环的形式)。

重新实现阶乘:

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

上面的代码能够完成阶乘任务,并且效率比递归要好的多。

有许多的问题都是以递归的方式实现的,这仅仅因为它比非递归的形式更加清晰,但是这些问题的迭代实现往往比递归实现效率更高。

然而,当一个问题难以使用迭代的方式解释清楚时,此时递归的简洁性便可以补偿它所带来的运行时的开销。

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

斐波那契数是不适合用递归的方式来解决的。

int Fib(int n)
{int a = 1;int b = 1;int c = 1;while (n >= 3){a = b;b = c;c = a + b;n--;}return c;}int main()
{	int n = 0;printf("请输入第几位的数:");scanf("%d", &n);int ret = Fib(n);printf("%d", ret);return 0;}

 当我们输入较小的数字时,运算的很快,当我们将 n 赋值为 50 时,上面的的代码是需要很长很长的时间才会运算出结果,这里就可以看见递归的缺点了,这是因为会进行很多的重复性计算,如下图所示: 

我们可以简单地进行重复计算的次数:

int count = 0;
int Fib(int i)
{if (i == 3)count++;if(i<=2)return 1;elsereturn Fib(i - 1) + Fib(i - 2);}int main()
{int n = 0;printf("请输入第几个数字:");scanf("%d", &n);int ret=Fib(n);printf("%d",ret);printf("\ncount=%d\n", count);return 0;
}

当我们输入 40 时,Fib(3)被执行的次数:

上面的运行结果表示的是,第3个斐波那契数被计算了39088169次,可以看出有关斐波那契数的计算用函数的递归方式是相当不明智的,我们就得用迭代的方式来实现。

int Fib(int n)
{int a = 1;int b = 1;int c = 1;while (n >= 3){a = b;b = c;c = a + b;n--;}return c;}int main()
{	int n = 0;printf("请输入第几位的数:");scanf("%d", &n);int ret = Fib(n);printf("%d", ret);return 0;}

用迭代的方式去实现时,就可以感觉到迭代的效率很高。当我们再次输入50时,不会需要很过的时间和空间去进行计算。

上面计算错误是因为超出了 int 的取值范围(需要修改返回的类型),但是很快的给出了结果。

所以有时递归虽然很好,但是不要迷恋递归。

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

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

相关文章

发票查验/发票验真如何用Java实现接口调用

一、什么是发票查验&#xff1f;发票验真接口&#xff1f; 输入发票基本信息发票代码、发票号码、开票日期、校验码后6位、不含税金额、含税金额&#xff0c;核验发票真伪。 该接口也适用于机动车、二手车销售发票、航空运输电子客票、铁路电子客票等。 二、如何用Java实现接口…

AM32-MultiRotor-ESC项目固件编译和烧录方法介绍

AM32-MultiRotor-ESC项目固件编译和烧录方法介绍 &#x1f4cd;AM32-MultiRotor-ESC项目地址:https://github.com/AlkaMotors/AM32-MultiRotor-ESC-firmware&#x1f388;Updater with V8 Bootloader&#xff1a; https://github.com/AlkaMotors/F051_Bootloader_Updater&#…

HarmonyOS:@AnimatableExtend 装饰器自学指南

在最近的项目开发中&#xff0c;我遇到了需要实现复杂动画效果的需求。在探索解决方案的过程中&#xff0c;我发现了 AnimatableExtend 装饰器&#xff0c;它为实现动画效果提供了一种非常灵活且强大的方式。然而&#xff0c;在学习这个装饰器的过程中&#xff0c;我发现相关的…

Windows server 2022域控制服务器的配置

Windows server 2022介绍 一、核心特性与改进 安全核心服务器&#xff08;Secured-Core Server&#xff09; 硬件级安全&#xff1a;支持基于硬件的安全功能&#xff08;如TPM 2.0、Secure Boot、基于虚拟化的安全防护VBS&#xff09;&#xff0c;防止固件攻击。受信任的启动链…

C++语法之模板函数和模板类

模板函数是什么&#xff1f;就是不指定类型的函数&#xff0c;不指定类型如何写代码?所以得用到模板&#xff0c;可以先用模板代替&#xff0c;就好像方程式&#xff0c;先用x,y代替一样。 它的写法是这样&#xff0c;定义函数时&#xff0c;开头加一句:(其中的T就相当于x,y之…

时序分析笔记

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、周期约束 二、建立时间和保持时间 三、时序路径 四、时序模型 前言 约束文件笔记&#xff0c;傅里叶的猫的视频。 一、周期约束 时序约束就是告诉软件输…

六十天前端强化训练之第二十八天之Composition 函数完全指南

欢迎来到编程星辰海的博客讲解 看完可以给一个免费的三连吗&#xff0c;谢谢大佬&#xff01; 目录 一、核心概念解析 1.1 什么是 Composition 函数 1.2 为什么需要封装 1.3 设计原则 二、实战案例&#xff1a;鼠标跟踪器 2.1 未封装版本 2.2 封装后的 Composition 函数…

MySQL 锁机制详解

MySQL 锁机制详解 5.1 概述 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中&#xff0c;除传统的计算资源&#xff08;CPU、 RAM、I/O&#xff09;的争用以外&#xff0c;数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有 效性是所有数…

常见中间件漏洞攻略-Apache篇

漏洞名称&#xff1a;Apache HTTP Server 路径穿越漏洞-CVE-2021-41773 第一步&#xff1a;拉取环境、启动环境 #拉取环境 docker pull blueteamsteve/cve-2021-41773:no-cgidhttp://121.40.229.129:8080#启动环境 docker run -dit -p 8080:80 blueteamsteve/cve-2021-41773:n…

站群服务器是什么意思呢?

站群服务器是一种专门为托管和管理多个网站而设计的服务器&#xff0c;其核心特点是为每个网站分配独立的IP地址。这种服务器通常用于SEO优化、提高网站权重和排名&#xff0c;以及集中管理多个网站的需求。以下是站群服务器的详细解释&#xff1a; 一、站群服务器的定义 站群…

Excel 小黑第22套

对应大猫22 新建一行&#xff0c;输入第一个人名字&#xff0c; 填充 -快速填充 修改员工编号&#xff08;1—001&#xff09;&#xff1a;选中所有员工编号&#xff0c;开始 -数据组 -自定义数字格式 000 在所有空表格单元格中输入数字0&#xff1a;选中修改的表格范围&#…

多传感器融合 SLAM LVI-SAM

目录 LVI-SAM 简介 A. 系统概述 B. 视觉惯导系统 C.雷达惯导系统 LVI-SAM 安装编译 编译 LVI-SAM 常见问题 LVI-SAM 工程化建议 LVI-SAM 简介 源码地址:https://github.com/TixiaoShan/LVI-SAM 如无法下载,换用 gitee 版本:https://gitee.com/inf_lee/LVI-SAM 改进…

Linux shell脚本3-if语句、case语句、for语句、while语句、until语句、break语句、continue语句,格式说明及程序验证

目录 1.if 控制语句 1.1 if 语句格式 1.2 程序验证 2.case语句 2.1case语句格式 2.2程序验证 2.2.1 终端先执行程序&#xff0c;在输入一个数 2.2.2 终端执行程序时同时输入一个预设变量 2.2.3 case带有按位或运算和通配符匹配 3.for语句 3.1for语句格式 3.2程序验…

图解模糊推理过程(超详细步骤)

我们前面已经讨论了三角形、梯形、高斯型、S型、Z型、Π型6种隶属函数&#xff0c;下一步进入模糊推理阶段。 有关六种隶属函数的特点在“Pi型隶属函数&#xff08;Π-shaped Membership Function&#xff09;的详细介绍及python示例”都有详细讲解&#xff1a;https://lzm07.b…

001-JMeter的安装与配置

1.前期准备 下载好JMeter : https://jmeter.apache.org/download_jmeter.cgi 下载好JDK : :Java Downloads | Oracle 中国 下载图中圈蓝的JMeter和JDK就行&#xff0c;让它边下载&#xff0c;我们边往下看 2.为什么要下载并安装JDK ? JMeter 是基于 Java 开发的工具&#…

英伟达有哪些支持AI绘画的 工程

英伟达在AI绘画领域布局广泛&#xff0c;其自研工具与第三方合作项目共同构建了完整的技术生态。以下是其核心支持AI绘画的工程及合作项目的详细介绍&#xff1a; 一、英伟达自研AI绘画工具 1. GauGAN系列 技术特点&#xff1a;基于生成对抗网络&#xff08;GAN&#xff09;&…

Netty源码—4.客户端接入流程二

大纲 1.关于Netty客户端连接接入问题整理 2.Reactor线程模型和服务端启动流程 3.Netty新连接接入的整体处理逻辑 4.新连接接入之检测新连接 5.新连接接入之创建NioSocketChannel 6.新连接接入之绑定NioEventLoop线程 7.新连接接入之注册Selector和注册读事件 8.注册Rea…

2025.3.17-2025.3.23学习周报

目录 摘要Abstract1 文献阅读1.1 动态图邻接矩阵1.2 总体框架1.2.1 GCAM1.2.2 输出块 1.3 实验分析 总结 摘要 在本周阅读的文献中&#xff0c;作者提出了一种名为TFM-GCAM的模型。TFM-GCAM模型的创新主要分为两部分&#xff0c;一部分是交通流量矩阵的设计&#xff0c;TFM-GC…

生活电子类常识——搭建openMauns工作流+搭建易犯错解析

前言 小白一句话生成一个网站&#xff1f;小白一句话生成一个游戏&#xff1f;小白一句话生成一个ppt?小白一句话生成一个视频&#xff1f; 可以 原理 总体的执行流程是 1&#xff0c;用户下达指令 2&#xff0c;大模型根据用户指令&#xff0c;分解指令任务为多个细分步骤…

深入解析 Uniswap:自动做市商模型的数学推导与智能合约架构

目录 1. 自动做市商&#xff08;AMM&#xff09;模型的数学推导1.1 恒定乘积公式推导1.2 价格影响与滑点 2. Uniswap 智能合约架构解析2.1 核心合约&#xff08;Core&#xff09;2.1.1 工厂合约&#xff08;Factory&#xff09;2.1.2 交易对合约&#xff08;Pair&#xff09; 2…