11.函数递归与迭代

news2024/9/28 3:31:03

递归与迭代

    • 1.什么是递归?
    • 2.递归的限制条件
    • 3.递归举例
      • 3.1 求n的阶乘
      • 3.2 顺序打印一个整数的每一位
    • 4.递归与迭代
      • 4.1 求第n个斐波那契数(递归 不推荐)
      • 4.2 求第n个斐波那契数(迭代 推荐)
      • 4.3 总结

1.什么是递归?

递归是一种解决问题的方法,递归就是函数自己调用自己。
例:

int main() {
	printf("调用函数main");
	main();
	return 0;
}

上述代码只是为了演示递归的形式,并非解决问题:
main函数中调用main函数,代码最终陷入死递归,无限调用main函数,最终导致栈溢出(overflow)

输出结果卡死,报错栈溢出
在这里插入图片描述
在这里插入图片描述

递归的思想:

把一个大型复杂的问题转化为一个与原问题相似,但是规模较小的子问题来求解,直到这个大型问题被拆分,递归就结束了。即大事化小的思路。


2.递归的限制条件

递归在书写格式上有2个必要条件:

1.递归存在限制条件,当满足这个限制条件的时候,递归便不再继续,停止。
2.每次递归调用之后越来越接近这个限制条件

以下举例几个递归的题目,来感受一下


3.递归举例

3.1 求n的阶乘

计算n的阶乘(不考虑溢出),n的阶乘就是1~n的数字累积相乘。
n的阶乘的公式:n! = n ∗ (n − 1)!

1.如果n等于0,则直接返回1,因为0的阶乘定义为1
2.否则,将n与(n-1)的阶乘结果相乘,并返回这个乘积
3.直至fact(n)中的n被减至0,跳出递归

在这里插入图片描述

//求n的阶乘
//计算n的阶乘(不考虑溢出),n的阶乘就是1~n的数字累积相乘。
int fact(int n) {
	if (n = 0) {//如果n等于0,则直接返回1,因为0的阶乘定义为1。
		return 1;
	}
	else//否则,将n与(n-1)的阶乘结果相乘,并返回这个乘积
	{
	
	//这里就是把一个大的数拆成了一个小的数乘上一个递归函数
	//直至fact(n)中的n被减至0,跳出递归
		return n * fact(n - 1);
	}
	return 0;
}

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

在这里插入图片描述

3.2 顺序打印一个整数的每一位

输⼊⼀个整数n,打印这个按照顺序打印整数的每⼀位
输⼊:1234 输出:1 2 3 4
输⼊:520  输出:5 2 0

n % 10 取最后一位
n / 10 去掉最后一位

void Print_Frist(int n) {
	if (n > 9) {
	//这里先递归再去打印最后一位
		Print_Frist(n / 10);
	}
	//打印最后一位
	printf("%d ", n % 10);
}

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

错误的思路:

void Print_Frist(int n) {
	if (n > 9) {
		//如果这里把n除以10,那么此次函数中的打印最后一位就会出问题
		n = n / 10;
		Print_Frist(n);
	}
	//打印最后一位,这里会出问题
	printf("%d ", n % 10);
}

原因:

例输入1234,if语句 中如果 n = n / 10
再去将n当作Print_Frist(n)函数的参数(这里确实没问题);但是,此次函数printf("%d “, n % 10);中的n也将随之改变,原先是4,n = n / 10之后变成3
函数递归调用时,此次函数尚未完全结束,即调用至Print_Frist(n)时,下面的printf(”%d ", n % 10)尚未执行
我们需要的只是将循环调用函数中的 参数/10 ,而本次函数中的n仍然不变


4.递归与迭代

强调一下,下列题目中,斐波那契数函数中 int Fibonacci(int n) 中的n仅仅是函数中的参数,从0开始;而参数为0的,为第一项,以此类推。(所以打印结果的时候会+1)
F(0) = 0 //第一项
F(1) = 1 //第二项

4.1 求第n个斐波那契数(递归 不推荐)

斐波那契数列是一个经典的数列,在数学上以如下递归关系定义:
F(0) = 0
F(1) = 1
F(n) = F(n-1) + F(n-2)
换句话说,斐波那契数列的前两项是0和1,之后的每一项都是前两项的和。
//递归方法
int count = 0;//调用函数次数
int Fibonacci(int n) {
	if (n <= 1) {
		count++;
		return n;
	}
	else{
		count++;
		return Fibonacci(n-1) + Fibonacci(n-2);
	}
}

int main() {
	int n;
	scanf("%d", &n);
    printf("第%d斐波那契数 = %d\n", n + 1, Fibonacci(n));
	printf("共调用了函数 %d 次\n",count);
	return 0;
}

在这里插入图片描述

不合适
这样计算确实可以得到正确的结果,但是这个函数一共调用了接近4千万次
C语言中每次调用函数都需要在栈区申请一块内存空间来保存函数调用期间的各种局部变量的值,这块空间被称为运行时堆栈,或者函数栈帧。
上述斐波那契数中 return Fibonacci(n - 1) + Fibonacci(n - 2) 这一步,在返回值这里再次递归调用函数,函数都尚未结束,空间都还没释放,就要再递归开辟一个新的内存空间,使得每一次递归都开辟一个新的栈帧空间,直至return开始回归,才会逐层释放栈帧空间。

4.2 求第n个斐波那契数(迭代 推荐)

迭代是一种重复执行某个操作或过程的方法。在编程中,迭代通常用于处理集合(如列表、数组等)中的每个元素,或者重复执行某个代码块直到满足特定条件。(顾名思义,就是更新迭代,把变量换成另一个新的变量

//迭代
int count = 0;
int Fibonacci(int n) {
    if (n <= 1) {
        count++;
        return n;
    }
    int a = 0;  // 第 0 项
    int b = 1;  // 第 1 项
    int fib = 0;  // 第 n 项

    for (int i = 2; i <= n; i++) {
        fib = a + b;
        //相当于都往后走了一位,因为这三个数是连续的
        a = b;
        b = fib;
        count++;
    }
    return fib;
}

int main() {
	int n;
	scanf("%d", &n);
	printf("第%d个斐波那契数 = %d\n",n+1, Fibonacci(n));
	printf("共执行了 %d 次\n",count);
	return 0;
}

在这里插入图片描述

上述代码使用了迭代效率相比于递归效率高出实在太多了,

4.3 总结

递归虽然是一种非常好的思路和想法,但是不能一昧的钻进递归中,任何方法都有自身的优点和缺点,所以具体问题具体分析,一种问题有多种解决方案,优先选择效率高的一种。

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

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

相关文章

奥威BI—数字化转型首选,以数据驱动企业发展

奥威BI系统BI方案可以迅速构建企业级大数据分析平台&#xff0c;可以将大量数据转化为直观、易于理解的图表和图形&#xff0c;推动和促进数字化转型的进程&#xff0c;帮助企业更好地了解自身的运营状况&#xff0c;及时发现问题并采取相应的措施&#xff0c;提高运营效率和质…

使用socket实现UDP版的回显服务器

文章目录 1. Socket简介2. DatagramSocket3. DatagramPacket4. InetSocketAddress5. 实现UDP版的回显服务器 1. Socket简介 Socket&#xff08;Java套接字&#xff09;是Java编程语言提供的一组类和接口&#xff0c;用于实现网络通信。它基于Socket编程接口&#xff0c;提供了…

【测试学习五】测试类型的划分(重点:白盒与黑盒测试)

目录 一、测试类型的分类 1、按测试对象划分 2、是否查看代码划分&#xff08;重点&#xff09; &#x1f337;&#xff08;1&#xff09;黑盒测试 &#x1f337;&#xff08;2&#xff09;白盒测试 &#x1f337;&#xff08;3&#xff09;灰盒测试 3、按照开发阶段划…

JVM分析工具JProfiler介绍及安装

目录 一、什么是JProfiler&#xff1f; 二、JProfiler 功能结构 1、分析代理 2、记录数据 3、快照 三、安装 一、什么是JProfiler&#xff1f; JProfiler是一个专业的工具&#xff0c;用于分析运行中的JVM内部发生的事情。当您的生产系统出现问题时&#xff0c;您可以…

FileZilla Server同时共享多个目录(手把手教你使用FileZilla Server同时设置多个目录)

网上的基本全是一句话带过怎么共享多个目录&#xff0c;没图很烦&#xff0c;所以我自己就写一个过程 目录 1、创建ftp用户并设置密码 1.1、进入用户管理 1.2、新建用户 1.3、设置密码 2、添加共享的目录 2.1、选择用户添加目录 2.2、给予用户访问权限 2.2.1、客户端访…

小程序服务器配置多大够用?

​  了解小程序服务器的大小和要求对于确保小程序的高效运行非常重要。下面将介绍小程序服务器的大小和要求&#xff0c;帮助您选择合适的服务器。 服务器费用 服务器费用因服务器类型、配置和带宽等因素而异。一般而言&#xff0c;小型小程序服务器的年费用在500元至2000元之…

SpringCloud之微服务API网关Gateway介绍

文章目录 1 微服务API网关Gateway1.1 网关简介1.2 Spring Cloud Gateway介绍1.3 Gateway特性1.4 Gateway核心概念1.4.1 路由1.4.1.1 定义1.4.1.2 动态路由 1.4.2 断言1.4.2.1 默认断言1.4.2.2 自定义Predicate 1.4.3 过滤器1.4.3.1 默认过滤器1.4.3.2 自定义Filter&#xff08;…

2023年第三届工业自动化、机器人与控制工程国际会议 | IET独立出版 | EI检索

会议简介 Brief Introduction 2023年第三届工业自动化、机器人与控制工程国际会议&#xff08;IARCE 2023&#xff09; 会议时间&#xff1a;2023年10月27 -30日 召开地点&#xff1a;中国成都 大会官网&#xff1a;www.iarce.org 2023年第三届工业自动化、机器人与控制工程国际…

【DMA】认识 DMA 及其工作流程

DMA&#xff08;Direct Memory Access&#xff09;&#xff0c;字面意思“直接访问内存”&#xff0c;无需 CPU 干预直接读写内存。传统CPU读写数据时&#xff0c;需要先将要使用的数据保存到 RAM&#xff0c;等要用时再从RAM 加载。 目录 一、传统CPU存取数据 二、认识DMA …

安防视频监控汇聚平台EasyCVR接入Ehome告警,公网快照不显示是什么原因?

智能视频监控汇聚平台TSINGSEE青犀视频EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等&#xff0c;视频监控管理平台…

openCV图像读取和显示

文章目录 一、imread二、namedWindow三、imshow #include <opencv2/opencv.hpp> #include <iostream>using namespace std; using namespace cv;int main(int argc,char** argv) {cv::Mat img imread("./sun.png"); //3通道 24位if (img.empty()) {std:…

App自动化测试|dom结构和元素定位方式

先来看几个名词和解释&#xff1a; dom: Document Object Model 文档对象模型 dom应用: 最早应用于html和js的交互。界面的结构化描述&#xff0c; 常见的格式为html、xml。核心元素为节点和属性 xpath: xml路径语言&#xff0c;用于xml 中的节点定位&#xff0c;XPath 可在 x…

ABAP 自定义搜索功能 demo1

ABAP 自定义搜索功能 demo1 效果&#xff1a; 双击选中行则为选中对应发票 实现 1定义 定义屏幕筛选参数 SELECTION-SCREEN BEGIN OF SCREEN 9020. SELECT-OPTIONS:s1_belnr FOR rbkp-belnr, s1_gjahr FOR rbkp-gjahr, s1_lifnr FOR rbkp-lifnr, s1_erfna FOR rbkp-erfnam, …

Go学习第四天

Interface空接口万能类型与类型断言机制 package mainimport "fmt"// interface{}是万能数据类型 func myFunc(arg interface{}) {fmt.Println("myFunc is celled....")fmt.Println(arg)// interface{} 该如何区分 此时引用的底层数据类型到底是什么&…

14-5_Qt 5.9 C++开发指南_基于HTTP 协议的网络应用程序

文章目录 1. 实现高层网络操作的类2. 基于HTTP协议的网络文件下载3.源码3.1 可是化UI设计3.2 mainwindow.h3.3 mainwindow.cpp 1. 实现高层网络操作的类 Qt 网络模块提供一些类实现 OSI 7 层网络模型中高层的网络协议&#xff0c;如 HTTP、FTP、SNMP等&#xff0c;这些类主要是…

linux Ubuntu 更新镜像源、安装sudo、nvtop

1.更换镜像源 vi ~/.pip/pip.conf在打开的文件中输入: pip.conf [global] index-url https://pypi.tuna.tsinghua.edu.cn/simple按下:wq保存并退出。 2.安装nvtop 如果输入指令apt install nvtop报错&#xff1a; E: Unable to locate package nvtop 需要更新一下apt&a…

MacBook Pro 16 M1 Max 升级 macOS Ventura 13.5 兼容测评

今天给大家带来了 MacBook Pro 16 M1 Max 升级 macOS Ventura 13.5 兼容 100 挑战赛 的视频&#xff0c;现在充电头再以文章的形式呈现给大家&#xff0c;让大家更清楚、直白的了解这款笔记本在升级系统后的兼容性如何。 MacBook Pro 16 M1 Max 配置了 140W 的 MagSafe 充电口&…

设备管理系统与物联网的融合:实现智能化设备监控和维护

在数字化时代&#xff0c;设备管理系统和物联网技术的融合为工业企业带来了巨大的变革和创新。本文将探讨设备管理系统与物联网的融合&#xff0c;重点介绍设备健康管理平台在实现智能化设备监控和维护方面的关键作用和优势。 一、设备管理系统与物联网的融合 随着物联网技术的…

37.利用linprog解 有约束条件多元变量函数最小值(matlab程序)

1.简述 linprog函数主要用来求线型规划中的最小值问题&#xff08;最大值的镜像问题&#xff0c;求最大值只需要加个“-”&#xff09; 2. 算法结构及使用方法 针对约束条件为Axb或Ax≤b的问题 2.1 linprog函数 xlinprog(f,A,b) xlinprog(f,A,b,Aeq,beq) xlinprog(f,A,b,Aeq,…

PROFINET转ETHERCAT协议网关三菱plc支持ethercat吗

捷米特JM–ECAT-PN是自主研发的一款 PROFINET 从站功能的通讯网关。该产品主要功能是将 PROFINET 网络和 ETHERCAT 网络连接起来。 捷米特JM-ECAT-PN连接到 PROFINET 总线中做为从站使用&#xff0c;连接到 ETHERCAT 总线中做为从站使用。 3.技术参数 PROFINET 技术参数 网关…