c语言的简易教法—— 函数递归

news2024/9/9 6:06:16

文章目录

  • 一、什么是递归?
    • 1.1递归的思想
    • 1.2递归的限制条件
  • 二、递归案例
    • 2.1 案例1:求n的阶层
      • 2.1.1分析
      • 2.1.2 递归函数(Fact)的代码实现
      • 2.1.3 测试:main函数实现
      • 2.1.4 运行结果和画图推演
      • 2.1.5 扩展:迭代方法求解n的阶乘
    • 2.2 案例2:顺序打印⼀个整数的每⼀位
      • 2.2.1分析
      • 2.2.2打印数(print)的每一位代码实现
      • 2.2.3 测试:print函数实现
      • 2.2.4 运行结果和画图推演
    • 2.3 案例3:求第n个斐波那契数
      • 2.3.1分析
      • 2.3.2求第n个斐波那契数(fib) 的代码实现
      • 2.3.3 测试:fib函数实现
      • 2.2.4 运行结果和画图推演
      • 2.1.5 扩展:迭代方法求解斐波那契数
    • 2.4 案例4:递归实现n的k次方
      • 2.4.1分析
      • 2.4.2 mypow函数实现
      • 2.4.3 测试:主函数实现mypow函数
      • 2.4.4 运行结果
  • 总结


一、什么是递归?

在代码运行中,有时候我们碰到冗长的代码无法进行下笔进行编码,这时候我们将会学习到应用函数递归进行运算。那么什么是递归呢?

1.1递归的思想

什么是函数递归?函数递归就是把大事化小,把小事在进行化小,直到解决问题。函数递归主要分为两个过程一个叫递推,一个叫回归。

递推主要是将大事简化成一个个小事逐渐往下进行,回归就是把最小的事情解决然后逐渐传递给上一个值进行回归计算值,直到返回最初需要解决的问题。

1.2递归的限制条件

递归存在两种限制条件 :

1.递归存在限制条件, 递推不能无限一直递推下去,即递推存在限制条件:什么时候进入递归,递归什么时候结束,递归存在进入递归的条件和递归的结束条件。只有满足这个限制条件,递归将不会继续递归下去。

为什么函数递归不能无限递归的原因

在这里插入图片描述

在这里我简单写了一个递归函数,内存中分为几个不同的区域,在函数运行中产生的局部变量都会存放在内存中的栈区,接着我们看到函数,首先进入主函数main,然后我们会创建一个栈帧空间存储main函数中的变量,然后代码继续运行下去我们调用test函数,调用test函数会开辟一个栈帧空间,在test函数中再次进行调用test函数就会出现如上图一样的情况,内存中的栈区也是有一定空间的,每次调用函数都会额外开辟一份空间,如果一直无限调用下去栈区将会溢出。

2.每次递归调⽤之后越来越接近这个限制条件

因为每次递归,相当于都是一次新的函数调用,而每次函数调用系统必须给该函数划分栈帧空间,内部的递归函数没有退出,上层的递归就不能退出,栈帧就会累积许多块,如果累积超过栈的总大小,就会栈溢出。所以函数递归每次都需要逐渐的接近这个函数递归的停止条件,否则他就会无限一直递归下去。


提示:以下是本篇文章代码部分,下面案例可供参考

二、递归案例

2.1 案例1:求n的阶层

⼀个正整数的阶乘(factorial)是所有⼩于及等于该数的正整数的积,并且0的阶乘为1。
⾃然数n的阶乘写作n!。

题⽬:计算n的阶乘(不考虑溢出),n的阶乘就是1~n的数字累积相乘。

2.1.1分析

在这里插入图片描述

上面分析图解中,我们就要有递归的思想:把一个较大的事情转化为一个与原问题相似,但规模较小的问题进行求解。

当n==0的时候,n的阶乘是1,其余的阶乘都是可以用如上图一样的规律可以推出来的。

递归公式

2.1.2 递归函数(Fact)的代码实现

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

2.1.3 测试:main函数实现

#include <stdio.h>
int Fact(int n)  
{
 if(n==0)  
   return 1;  
 else  
   return n*Fact(n-1);  
}
int main()  
{
 int n = 0;  
 scanf("%d", &n);  
 int ret = Fact(n);  
 printf("%d\n", ret);  
 return 0;  
}

2.1.4 运行结果和画图推演

注意此处不考虑n太大,n太大会存在溢出的情况,因为这是一个整型变量,存储的最大值65530
在这里插入图片描述

在这里插入图片描述

2.1.5 扩展:迭代方法求解n的阶乘

#include<stdio.h>

int Fact(int n)
{
	int i = 0;
	int sum = 1;
	for (i = 1; i <= n; i++)
	{
		sum = sum * i;
	}
	return sum;
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = Fact(n);>   
	printf("%d\n", ret);   
	return 0;   
}

2.2 案例2:顺序打印⼀个整数的每⼀位

题目:输⼊⼀个整数m,打印这个按照顺序打印整数的每⼀位。
例如:

输入1234,打印1 2 3 4
输入4578,打印4 5 7 8

2.2.1分析

首先看到打印的第一步,我们想到的是怎么求出该数的每一位:
如果该数是一位数,那我们直接打印这一位即可。
如果该数超过一位数,那我们就得一个个求出该数的每一位。

假如我们要打印1234的每一位,我们得先求出他的每一位

1234 % 10 = 4,在这里我们得到了个位上的数4。 1234 / 10 = 123;
123 % 10 = 3, 在这里我们得到了十位上的数3。 123 / 10 = 12;
12 % 10 = 2,在这里我们得到了百位上的数2。 12 / 10 =1;
1 % 10 = 1 ,此时一位数我们直接打印即可。1 / 10 =0;由这里可以判断结束递归的条件是该数大于9.
但是这里发现最先得到的是个位上的数,因此我们这里弄出一个函数print
print(1234) = print(123) + printf(4);= print(1234/10) + printf(1234%10)
print(123) = print(12) + printf(3) + printf(4) ; = print(123/10) + printf(123%10)
print(12) = printf(1) + printf(2)+ printf(3) + printf(4) ;

2.2.2打印数(print)的每一位代码实现

void Print(int n) voidPrint(国际)       
{
 if(n>9) 如果(n>9{
   Print(n/10); 打印(n/10;       
 }
   printf("%d ", n%10); printf(“%d ”,n%10;       
}

2.2.3 测试:print函数实现

#include<stdio.h>
void Print(int n)  
{
 if(n>9)  
 {
   Print(n/10);  
 }
   printf("%d ", n%10);  
}
int main()
{
 int m = 0;
 scanf("%d", &m);
 Print(m);
 return 0;
}

2.2.4 运行结果和画图推演

在这里插入图片描述
在这里插入图片描述

2.3 案例3:求第n个斐波那契数

题目:求第n个斐波那契数;

输入: 5 输出:5
输入:10 输出:55

2.3.1分析

有不知道什么叫斐波那契数列的同学可以百度搜索详细了解一下,在这里小编就简单给大家介绍一下什么叫斐波那契数列。斐波那契数第n个数等于前两个数之和的相加,因此斐波那契数列第一第二个数都为1,以此推导剩下的斐波那契数:
1 1 2 3 5 8 13 21 34 55 。。。。
因此我们可以推导出求第n个斐波那契数的公式为:
在这里插入图片描述

2.3.2求第n个斐波那契数(fib) 的代码实现

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

2.3.3 测试:fib函数实现

#include<stdio.h>
int fib(int n)
{
	if (n <= 2)
		return 1;
	else
		return fib(n - 1) + fib(n - 2);
}
int main()
{
	int m = 0;
	scanf("%d", &m);
	int ret = fib(m);
	printf("%d ",ret);
	return 0;
}

2.2.4 运行结果和画图推演

在这里插入图片描述

在这里插入图片描述

2.1.5 扩展:迭代方法求解斐波那契数

在上面细心的人就会发现我们求解第50个斐波那契数,电脑突然间疯狂的转起来,但是始终等了很久也没有得到第50个斐波那契数的值,这是为什么呢?

在这里插入图片描述

由上面的图我们可以看出,当我们在进行递归运算的时候,他会重复计算很多的重复值,例如我们上面再递归求fib(49)需要求fib(48)和fib(47);而我们求fib(48)又会求一次fib(47)和fib(46),这时随着递归的层次原来越深,我们会发现我们会重复计算很多次重复的值,接下来我们计算一下算fib(3)一共计算了多少次。

#include<stdio.h>
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 m = 0;
	scanf("%d", &m);
	int ret = fib(m);
	printf("%d\n",ret);
	printf("count = %d",count);
	return 0;
}

在这里插入图片描述

这时我们可以发现fib(3)重复计算了39088619次,这大大加大了计算机运行的难度,因此求解斐波那契数的时候递归求解是一个错误的选择。因此我们可以直接采用迭代的求法。

#include<stdio.h>
int fib(int n)
{
	int a = 1; //开始时第一个斐波那契数
	int b = 1; //开始时第二个斐波那契数
	int c = 1; //返回求解的斐波那契数,因为如果n<=2返回1所以c的初始值为1

	while (n > 2)
	{
		c = a + b;
		a = b; 
		b = c; 
		n--; 
	}
	return c; 
}
int main() 
{
	int m = 0; 
	scanf("%d", &m); 
	int ret = fib(m); 
	printf("%d\n",ret); 
	return 0; 
}

2.4 案例4:递归实现n的k次方

模拟实现pow函数实现求解n的k次方

输入:2 3 输出:8
输入:3 3 输出:27

2.4.1分析

当k的值为0的时候,返回1;
当k的值为1的时候,返回n;
当k的值大于1的时候,返回n*mypow(k-1);
综上:
在这里插入图片描述

2.4.2 mypow函数实现

int mypower(int k, int n)
{

	if (n == 0)
		return 1;
	else if(n >= 1)
		return k * mypower(k, n - 1);
}

2.4.3 测试:主函数实现mypow函数

int mypower(int k, int n)
{
	if (n == 0)
		return 1;
	else if(n >= 1)
		return k * mypower(k, n - 1);
}
int main()
{
	int k = 0;
	int n = 0;
	scanf("%d%d", &k, &n);
	int ret = mypower(k, n); 
	printf("%d ", ret); 
	return 0;  

}

2.4.4 运行结果

在这里插入图片描述


总结

通过上面案例我们初步了解了函数递归的思想 :把大事化小的特点。明白函数递归的充要条件是1,首先要有限制条件,即进入递归的条件和结束递归的条件。2,在函数递归的时候我们要逐渐的接近这个递归条件。
当然函数递归的学习远不如于此,需要大家在不断的实践练习中不断了解函数递归的妙用。这是小编对于函数递归的理解如果有读者有看不懂的地方或者更好的建议欢迎评论下方留言。

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

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

相关文章

纹波电流与ESR:解析电容器重要参数与应用挑战

电解电容纹波电流与ESR&#xff08;Equivalent Series Resistance&#xff09;是电容器的重要参数&#xff0c;用来描述电容器对交流信号的响应能力和能量损耗。电解电容纹波电流是指电容器在工作时承受的交流信号电流&#xff0c;而ESR则是电容器内部等效电阻&#xff0c;影响…

2024年PMP报考需要什么条件?怎么报名?

PMP报名条件要求不高&#xff0c;只要满足下面两个条件&#xff1a; 1、35个PDU &#xff08;需要有 PMI 授权的机构颁发&#xff09; 2、项目经验 学士学位需要 4500 个小时的项目管理经验&#xff0c;3年工作经验&#xff1b; 非学士学位需要 7500 个小时的 项目管理经验&…

机器视觉:(1) 初识Roboflow(使用详解一)获取数据集(最新)

一&#xff1a;访问地址 [1] Roboflow官网&#xff1a;官网地址 [2]YOLOv8 项目地址github源码地址 [3]YOLOv8 官方教程官网教程地址 二&#xff1a;获取数据集步骤 1.访问官网地址&#xff1a;进入首页面&#xff0c;点击登录 2.注册过程省略了&#xff0c;按步骤走就可以…

Qt:18.状态栏(状态栏介绍、代码方式创建状态栏、在状态栏显示临时信息、在状态栏创建控件)

目录 1.状态栏介绍&#xff1a; 2.代码方式创建状态栏&#xff1a; 3. 在状态栏显示临时信息&#xff1a; 4.在状态栏创建控件&#xff1a; 1.状态栏介绍&#xff1a; Qt 状态栏是 QMainWindow 窗口的一部分&#xff0c;通常用于显示临时信息&#xff0c;如应用程序的状态、…

myeclipse开发ssm框架项目图书管理系统 mysql数据库web计算机毕业设计项目

摘 要 随着计算机的广泛应用&#xff0c;其逐步成为现代化的标志。图书馆的信息量也会越来越大&#xff0c;因此需要对图书信息、借书信息、还书信息等进行管理&#xff0c;及时了解各个环节中信息的变更&#xff0c;要对因此而产生的单据进行及时的处理&#xff0c;为了提高高…

【YashanDB知识库】YashanDB 开机自启

【问题分类】 YashanDB 开机自启 【关键字】 开机自启&#xff0c;依赖包 【问题描述】 数据库所在服务器重启后只拉起monit、yasom、yasom进程&#xff0c;缺少yasdb进程&#xff1a; 【问题原因分析】 数据库安装的时候未启动守护进程 【解决 / 规避方法】 进入数据库之前…

分别通过LS和RML进行模型参数辨识matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1 最小二乘法(LS)参数辨识 4.2 递归最大似然估计(RML)参数辨识 5.完整程序 1.程序功能描述 分别通过LS和RML进行模型参数辨识matlab仿真&#xff0c;仿真输出参数辨识的误差&#xff0c…

【Linux】Linux背景历史

Linux背景历史 Linux背景Linux是什么&#xff1f;计算机的发展unix发展史Linux发展史开源Linux官网以及版本更替Linux企业应用现状 Linux环境的安装 Linux背景 Linux是什么&#xff1f; Linux(Linux Is Not UniX)&#xff0c;一般指GNU/Linux&#xff0c;是一种免费使用和自由…

边缘计算网关:一种高效安全的工业物联网解决方案-天拓四方

在工业物联网&#xff08;IIoT&#xff09;领域&#xff0c;数据处理和实时响应的需求日益增长&#xff0c;尤其是在智能制造、远程监控和预测性维护等场景中。边缘计算网关作为一种前端数据处理和决策设备&#xff0c;正逐渐成为满足这些需求的理想解决方案。 在一个大型制造…

前端JS特效第30波:jquery图片列表按顺序分类排列图片组效果

jquery图片列表按顺序分类排列图片组效果&#xff0c;先来看看效果&#xff1a; 部分核心的代码如下&#xff1a; <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> &…

智慧景区综合解决方案PPT(53页)

智慧景区综合解决方案摘要 建设背景 智慧景区综合解决方案在文旅融合、政策支撑和行业背景三大背景下提出。文旅融合强调文化和旅游的结合&#xff0c;政策支撑如《“十三五”全国旅游信息化规划》和《江苏省文化和旅游厅2019年工作要点》为智慧旅游提供指导&#xff0c;行业背…

C++相关概念和易错语法(18)(array、模板)

1.array &#xff08;1&#xff09;普通数组的劣势 当我们直接越界修改值时&#xff0c;一般会在编译时就被拦截 但是越界访问&#xff0c;只要访问距离不算特别大&#xff0c;那么也可以越界访问 当我们不直接越界修改或访问&#xff0c;间接去访问和修改能越界非常远 这里的…

AWS认证考试流程:从准备到通过

AWS认证是IT行业中备受推崇的专业资格认证之一&#xff0c;它不仅可以验证您的AWS技能&#xff0c;还能提升您的职业竞争力。本文将为您详细介绍AWS认证考试的完整流程&#xff0c;从初步准备到最终通过认证。 选择适合的认证级别 AWS提供多个级别的认证&#xff0c;包括&…

Java中的LinkedList(链表)(如果想知道Java中有关LinkedList的知识点,那么只看这一篇就足够了!)

前言&#xff1a;在Java编程语言中&#xff0c;Java集合框架提供了一组丰富的数据结构&#xff0c;以满足各种应用需求。其中&#xff0c;LinkedList作为一种常用的数据结构&#xff0c;具有独特的优势和广泛的应用场景。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内…

MesooRF:经典蓝牙模块与低功耗蓝牙模块如何区分?

从蓝牙4.0开始&#xff0c;有两种蓝牙芯片模块&#xff1a;经典蓝牙模块(BT)和低能耗(BLE)蓝牙模块。 经典蓝牙是在之前的蓝牙1.0&#xff0c;1.2&#xff0c;EDR 2.0&#xff0c;EDR 2.1&#xff0c;EDR 3.0的基础上发展完善的&#xff0c;而低功耗蓝牙是在Nokia的Wibree标准上…

客户关系管理怎么做?这4个工具一定要会用!

在商海浮沉中&#xff0c;每一位企业家和销售经理都深知&#xff0c;客户是企业生存与发展的基石。但如何有效管理这些宝贵的资源&#xff0c;让每一次互动都成为加深关系、促进成交的契机&#xff0c;却是一门艺术加科学的结合体。今天&#xff0c;咱们就来聊聊客户关系管理&a…

79. UE5 RPG 创建技能冷却和消耗

在这一篇里面&#xff0c;我们接着优化技能&#xff0c;现在角色添加的主动技能能够同步到ui上面。我们在这一篇文章里面&#xff0c;完善技能的消耗&#xff08;释放技能减少蓝量&#xff09;和冷却机制。 我们可以看到&#xff0c;在技能类默认值这里&#xff0c;可以设置它的…

AIGC时代创意设计师从“创作”向“智作”升级

随着人工智能技术的飞速发展&#xff0c;AIGC&#xff08;AI Generated Content&#xff0c;即人工智能生成内容&#xff09;时代已经到来&#xff0c;为创意设计领域带来了前所未有的变革。在这一时代背景下&#xff0c;创意设计师们正经历着从传统的“创作”向“智作”的转型…

SCSA第五天

NAT 静态NAT 动态NAT Napt 一对多 --- easy ip 多对多的NAPT 服务器映射 源NAT --- 基于源IP地址进行转换&#xff0c;包含静态NAT&#xff0c;动态NAT以及NAPT 目标NAT --- 基于目标IP地址进行转换&#xff0c;以前的端口映射 双向NAT --- 同时转换源IP地址和目标IP地…

SpringSecurity中文文档(Servlet Authorization Architecture )

Authorization 在确定了用户将如何进行身份验证之后&#xff0c;还需要配置应用程序的授权规则。 Spring Security 中的高级授权功能是其受欢迎的最有说服力的原因之一。无论您选择如何进行身份验证(无论是使用 Spring Security 提供的机制和提供者&#xff0c;还是与容器或其…