C语言--函数递归

news2024/11/18 9:03:07

目录

1、什么是递归?

1.1 递归的思想

1.2 递归的限制条件

2. 递归举例

2.1 举例1:求n的阶乘

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

 3. 递归与迭代

扩展学习:


早上好,下午好,晚上好

1、什么是递归?
 

递归其实是⼀种解决问题的⽅法,在C语⾔中,递归就是函数 ⾃⼰调⽤⾃⼰
写⼀个史上最简单的C语⾔递归代码:
#include <stdio.h>
int main()
{
 printf("hehe\n");
 main();//main函数中⼜调⽤了main函数
 return 0;
}
上述就是⼀个简单的递归程序,只不过上⾯的递归只是为了演⽰递归的基本形式,不是为了解决问
题,代码最终也会陷⼊死递归,导致栈溢出

1.1 递归的思想

把⼀个⼤型复杂问题层层转化为⼀个与原问题相似,但规模较⼩的⼦问题来求解;直到⼦问题不能再 被拆分,递归就结束了。所以递归的思考⽅式就是把⼤事化⼩的过程。
递归中的 递就是递推 的意思, 归就是回归 的意思

1.2 递归的限制条件

递归在书写的时候,有2个必要条件:
递归存在 限制条件 ,当满⾜这个限制条件的时候,递归便不再继续。
每次递归调⽤之后 越来越接近 这个限制条件

2. 递归举例

2.1 举例1:求n的阶乘

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

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

 n的阶乘的公式: n! =  n ∗ (n − 1)!

举例:
       5! = 5*4*3*2*1
       4! = 4*3*2*1
 所以: 5! = 5*4!
这样的思路就是把⼀个较⼤的问题,转换为⼀个与原问题相似,但 规模较⼩ 的问题来求解的。
n==0 的时候,n的阶乘是1,其余n的阶乘都是可以通过公式计算。
n的阶乘的递归公式如下:

 

 

那我们就可以写出函数 Fact求n的阶乘 ,假设 Fact(n)就是求n的阶乘 ,那么 Fact(n-1)就是求n-1 的阶
乘,如下:
#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.2 举例2:顺序打印⼀个整数的每⼀位

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

 

1234%10就能得到4,然后1234/10得到123,这就相当于去掉了4
然后继续对123%10,就得到了3,再除10去掉3,以此类推
不断的 %10 /10 操作,直到1234的每⼀位都得到
但是这⾥有个问题就是得到的数字顺序是倒着的
但是我们有了灵感,发现其实⼀个数字的最低位是最容易得到的,通过%10就能得到
那我们假设想写⼀个函数Print来打印n的每⼀位,如下表⽰:
Print(n)
如果n是1234,那表⽰为
Print(1234) //打印1234的每⼀位

其中1234中的4可以通过%10得到,那么
Print(1234)就可以拆分为两步:
1. Print(1234/10) //打印123的每⼀位
2. printf(1234%10) //打印4
完成上述2步,那就完成了1234每⼀位的打印

那么Print(123)⼜可以拆分为Print(123/10) + printf(123%10)
以此类推下去,就有
Print(1234)
==>Print(123) + printf(4)
==>Print(12) + printf(3)
==>Print(1) + printf(2)
==>printf(1)
直到被打印的数字变成⼀位数的时候,就不需要再拆分,递归结束。
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;
}
在这个解题的过程中,我们就是使⽤了⼤事化⼩的思路
把Print(1234) 打印1234每⼀位, 拆解为 ⾸先 Print(123) 打印123的每⼀位,再打印得到的4
把Print(123) 打印123每⼀位,拆解为⾸先 Print(12) 打印12的每⼀位,再打印得到的3
直到Print打印的是 ⼀位数 ,直接打印就⾏。
画图推演:

 3. 递归与迭代

递归是⼀种很好的编程技巧,但是和很多技巧⼀样,也是可能被误⽤的
在C语⾔中每⼀次函数调⽤,都要需要为本次函数调⽤在栈区 申请⼀块内存空间 来保存函数调⽤期间的各种局部变量的值,这块空间被称为 运⾏时堆栈 ,或者 函数栈帧
函数不返回,函数对应的栈帧空间就 ⼀直占⽤ ,所以如果函数调⽤中存在递归调⽤的话,每⼀次递归函数调⽤都会开辟属于⾃⼰的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间。
所以如果采⽤函数递归的⽅式完成代码,递归 层次太深 ,就会 浪费 太多的栈帧空间,也可能引起 栈溢出 的问题

 

所以如果不想使⽤递归就得想其他的办法,通常就是迭代的⽅式(通常就是循环的⽅式)。
⽐如:计算n的阶乘,也是可以产⽣1~n的数字累计乘在⼀起的。
int Fact(int n)
{
 int i = 0;
 int ret = 1;
 for(i=1; i<=n; i++)
 {
 ret *= i;
 }
 return ret;
}
举例:求第n个斐波那契数
我们也能举出更加 极端的例⼦ ,就像计算第n个斐波那契数,是不适合使⽤递归求解的,但是斐波那契数的问题通过是使⽤递归的形式描述的,如下:

 

 看到这公式,很容易诱导

#include <stdio.h>
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的时候,需要很⻓时间才能算出结果,这个计算所花费的时间,是我们很难接受的,这也说明递归的写法是 ⾮常低效 的,那是为什么呢

 

其实递归程序会不断的展开,在展开的过程中,我们很容易就能发现,在递归的过程中会有 重复
算,⽽且递归层次越深, 冗余计算 就会越多。
我们知道斐波那契数的前2个数都1,然后前2个数相加就是第3个数,那么我们从前往后,从⼩到⼤计算就⾏了。
这样就有下⾯的代码:
int Fib(int n)
{
 int a = 1;
 int b = 1;
 int c = 1;
 while(n>2)
 {
 c = a+b;
 a = b;
 b = c;
 n--;
 }
 return c;
}
迭代的⽅式去实现这个代码, 效率 就要⾼出很多了。
有时候,递归虽好,但是也会引⼊⼀些问题,所以我们⼀定不要迷恋递归, 适可⽽⽌ 就好。

扩展学习:

汉诺塔问题(经典递归问题)

汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?

 

 假设总共需要移动n个盘子
1.将A柱上的n-1个盘子借助C柱移向B柱
2.将A柱上仅剩的最后一个盘子移向C柱
3.将B柱上的n-1个盘子借助A柱移向C柱

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

void move(int x, int y)
{
	printf("%c->%c\n", x, y);
}
void hanoi(int n, char a, char b, char c)
{
	if (n == 1)
	{
		move(a, c);
	}
	else
	{
		hanoi(n - 1, a, c, b);//将A座上的n-1个盘子借助C座移向B座
		move(a, c);//将A座上最后一个盘子移向C座
		hanoi(n - 1, b, a, c);//将B座上的n-1个盘子借助A座移向C座
	} 
}
//move中的实参与hanoi函数中的形参相对应,而hanoi函数中形参a,b,c所对应的值也是在有规律的变化
int main()
{
	int n = 0;
	scanf("%d", &n);
	hanoi(n, 'A', 'B', 'C');
	return 0;
}

 感谢观看

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

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

相关文章

【Web】DASCTF X CBCTF 2022九月挑战赛 题解

目录 dino3d Text Reverser cbshop zzz_again dino3d 进来是一个js小游戏 先随便玩一下&#xff0c;显示要玩够1000000分 直接console改分数会被检测 先是JSFinder扫一下&#xff0c;扫出了check.php 到js里关键词索引搜索check.php 搜索sn&#xff0c;发现传入的参数是…

上古掌控安全的神-零:Spring Security5.x到Spring Security6.x的迁移

1. 本文概述 之前有写过一篇关于Spring Security的文章&#xff0c;但那已经是相对比较旧的版本了&#xff0c;就目前Spring Security6.0来说&#xff0c;这其中出现了不少的变动和更新&#xff0c;很多API的使用也是有不小的变化&#xff0c;所以我觉得有必要再写几篇文章学习…

OpenCV4.10使用形态运算提取水平线和垂直线

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;OpenCV的查找命中或未命中 下一篇&#xff1a;OpenCV4.9图像金字塔-CSDN博客 目标 在本教程中&#xff0c;您将学习如何&#xff1a; 应用两个非常常见的形态运算符&#xff08;即膨胀和…

java/C#语言开发的医疗信息系统10套源码

java/C#语言开发的医疗信息系统10套源码 云HIS系统源码&#xff0c;云LIS系统源码&#xff0c;PEIS体检系统&#xff0c;手麻系统 源 码&#xff0c;PACS系统源码&#xff0c;微源预约挂号源码&#xff0c;医院绩效考核源码&#xff0c;3D智能导诊系统源码&#xff0c;ADR药物…

数据分析场景,连号相关业务

连号相关业务 业务场景&#xff1a;现在需要从a列一堆编号中&#xff0c;将连号范围在10以内的数据分别分成一组。 先看实先效果 演示的为db2数据库&#xff0c;需要含有窗口函数&#xff0c;或者可以获取到当前数据偏移的上一位数据 第一步&#xff1a;将A列数据正序第二步…

【笔试强训_Day06】

文章目录 1.字符串相乘 1.字符串相乘 题目链接 解题思路&#xff1a; 高精度乘法&#xff0c;注意要学会下面这种列式相乘的形式&#x1f34e; 注意细节❗&#xff1a; ① &#x1f34e; 首先把列式相乘的数据都存放到数组中去&#xff0c; 然后再对数组中的数据进行取余进…

Web开发:ASP.NET CORE的前端demo(纯前端)

目录 一、建立项目 二、删除无用文件 三、样式添加 四、写一个登录页面 五、登录主界面 一、建立项目 二、删除无用文件 三、样式添加 将你的图片资源添加在wwwroot下方&#xff0c;例如pics/logo.png 四、写一个登录页面 将Privacy.cshtml改为 Forget.cshtml &#xff0…

喜报 | 英码科技顺利通过2023年度广东省工程技术研究中心认定

近日&#xff0c;广东省科学技术厅公示了2023年度广东省工程技术研究中心的名单&#xff0c;英码科技设立的“广东省人工智能与边缘计算工程技术研究中心”顺利通过2023年度广东省工程技术研究中心的认定&#xff1b;英码科技在边缘计算领域的技术创新能力、科技成果转化再次获…

452. 用最少数量的箭引爆气球[排序+贪心]

https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/description/?envTypestudy-plan-v2&envIdtop-interview-150 题目描述 有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points &#xff0c;其中points[i] [xst…

ZooKeeper写数据流程

ZooKeeper写数据流程 初始化连接&#xff1a; 客户端初始化与 ZooKeeper 集群的连接&#xff0c;连接可以是 TCP 连接或者基于 UDP 的通信。客户端可以连接到集群中的任何一个节点。 查找 Leader&#xff1a; 当客户端发送写请求时&#xff0c;如果连接的节点不是 Leader&…

最新版frp将家里的nas机器内网穿透(含域名配置)

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。 前言 最近&#xff0c;家里整了个nas,自此开始入坑nas,由于是黑群晖&#xff0c;所以没有带公网访问的功能&#xff0c;只能自己研究了。 好在之前用过frp&#xff0c;整过内网穿透&…

springboot+vue社区报修便民维修网站设计与实现

便民维修网站&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、管理员管理、用户管理、维修人员管理、在线报修管理、联系客服管理、公司回访管理、基础数据管理、论坛管理、公告管理、轮播图信息&#xff0c;维修人员&#xff1b;首页、个人中心、维修人员评价管…

ViM-UNet:用于生物医学细分的 Vision Mamba

ViM-UNet&#xff1a;用于生物医学细分的 Vision Mamba 摘要IntroductionMethod and Experiments结果与讨论 ViM-UNet: Vision Mamba for Biomedical Segmentation 摘要 卷积神经网络&#xff08;CNNs&#xff09;&#xff0c;尤其是UNet&#xff0c;是生物医学分割的默认架构…

springboot+java照相馆预约管理系统ssm

框架&#xff1a;ssm/springboot都有 jdk版本&#xff1a;1.8 及以上 ide工具&#xff1a;IDEA 或者eclipse 数据库: mysql 编程语言: java 前端&#xff1a;layuibootstrapjsp 详细技术&#xff1a;HTMLCSSJSjspspringmvcmybatisMYSQLMAVENtomcat 开发工具 IntelliJ IDEA: 一…

利用二维码定位技术实现桌面机器人简易定位方案(下篇)

目录 1、前言2、定位标签定义3、识别算法流程4、python编程4.1 查找三个回字定位点python4.2 根据三个定位点坐标位置关系&#xff0c;进行识别python4.3 根据实际坐标对当前图像进行矫正python4.4 计算物体的坐标值python 总结本篇对应python源码 1、前言 机械手臂尤其是工业…

vue全屏后下拉框失效

如图&#xff0c;vue页面有个全屏功能 问题&#xff1a;全屏后下拉菜单消失 解决&#xff1a;加个这个 :teleported"false"如果不行试试这个 :popper-append-to-body"false"ok我话说完

【1425】java 外籍人员管理系统Myeclipse开发mysql数据库web结构jsp编程servlet计算机网页项目

一、源码特点 java 外籍人员管理系统是一套完善的java web信息管理系统 采用serlvetdaobean&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式 开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff…

Mac M3 安装Ollama和llama3,本地部署LobeChat和刘皇叔聊三国!

OllamaLobeChat&#xff0c;本地部署聊天助手 Ollama安装下载OllamaOllama常用指令和链接运行OllamaAPI 交互Ollama基于Llama 3角色扮演 LobeChat安装首先安装docker安装LobeChat的docker 镜像和运行 Ollama安装 下载Ollama 网址&#xff1a;https://ollama.com/ 支持macOS、…

每日一题(L2-011):玩转二叉树--建树+层序遍历

与L2-006近乎相同&#xff0c;先建树&#xff0c;然后遍历 #include<bits/stdc.h> using namespace std; int in[35]; int pre[35]; typedef struct Tree{int num;Tree* left;Tree* right; }T;T * build(int in1,int in2,int pre1,int pre2){T * tnew T;t->numpre[pr…

代码优化实践之税率计算问题

开篇 今天的问题来自于《编程珠玑》第三章【数据决定程序结构】&#xff0c;这里提出了几条代码优化相关的原则&#xff0c;受益不浅。下面是提到的几条原则&#xff1a; 使用数组重新编写重复代码。冗长的相似代码往往可以使用最简单的数据结构——数组来更好的表述&#xff1…