再识C语言 DAY13 【递归函数(超详细)】
文章目录
- 前言
- 一、函数递归
- 什么是递归
- 递归的两个重要条件
- 练习一
- 练习二
- ==递归与迭代==
- 练习三
- 练习四
- ==在练习三、四中出现的问题==
- 如果您发现文章有错误请与我留言,感谢
前言
本文总结于此文章
一、函数递归
什么是递归
函数调用自身的编程技巧称为递归
(函数自己调用自己)
递归分为**递推和回归**
递归的策略
它通常把一个大型复杂的问题层层转换为一个与原问题相似的小问题来解决。
递归的重要思想:把大事化小
例如(史上最简单的递归):
#include<stdio.h>
int main()
{printf("Hello World\n");main();
}
先一直打印 Hallo World,最终程序挂掉

递归的两个重要条件
因当存在限制条件,当满足这个限制条件时递归便不再继续。
每次递归调用之后越来越接近这个限制条件。
练习一
接受一个整型值(无符号),按顺序打印他的每一位
例如:
输入:1234,输出 1 2 3 4
我们的第一想法就是:
1234%10 = 41234/10=123123%10=3123/10=1212%10=212/10=11%10=11/10=0
这样我们能得到数字的每一位,然后我们把他们打印出来
#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS
int main()
{int a ,n;printf("请输入一个无符号的整型:");scanf("%d", &a);
while(a>10){if(a>10){n = a % 10;printf("\n%d ",n);a = a / 10;}
}printf("\n%d",a);return 0;
}

我们发现输出结果和题目中的不同,这个问题需要我们用递归来进行
因为递归的原理是先递推再回归,一层一层的传递下去
我们定一个print函数,它的功能是按照顺序打印num的每一位。
打印1234的每一位:print(1234)
打印1234的每一位,我们可以先打印123的每一位再打印4
打印123的每一位:我们可以先打印12的每一位print(12)再打印3
打印12的每一位:我们可以先打印1的每一位print(1)再打印2
最后输出打印1 2 3 4
程序:
print(1234)
print(123) 4
print(12) 3 4
print(1) 2 3 4
最终输出:1 2 3 4
在写代码的过程中,我们只需要关注最后一层的递推和回归

我们的想法就是先把余的1打印出来,再把上一层余的2打出来,以此类推。
此时我们的n等于1 ,用来打印余1
printf("%d ",n%10);
因为这是我们上一层所调用的print函数,当这个函数执行完后,我们还要回到上一层,继续执行代码
此时n等于12,打印出来的结果为2。
printf("%d ",n%10);
依次循环,这就是我们的递归
首先,我们先把递归函数写出来
void print(int n){if(n<10){printf("%d ",n);}else{print(n/10);printf("%d ",n%10); }
}
代码实现:
#include <stdio.h>void print(int n){if(n<10){printf("%d ",n);}else{print(n/10);printf("%d ",n%10); }
}int main (){ int a=0;printf("输入一个数字\n");scanf("%d",&a);print(a);return 0;
}

当然也可以更简便:
其更简便的最根本的原因是限制条件不同,使用n>9时,就不用使用else
#include<stdio.h>
void print(unsigned int n)
{if (n > 9)限制条件{print(n / 10);每次递归调用之后越来越接近这个限制条件}printf("%d ", n % 10);
}
int main()
{unsigned int num = 0;scanf("%u", &num);print(num);return 0;
}
练习二
写一个可以求字符串长度的代码(老朋友了已经是)
我们有一个专门求字符串长度的库函数 strlen
长度等于开始到空字符之间的字符数(不包括空字符本身)\0
首先我们先创建一个字符数组
char arr[] = "abc";
再用strlen函数
#include<stdio.h>
#include<string.h>
int main()
{char arr[] = "abc";strlen(arr);printf("%d", strlen(arr));return 0;
}
我们自己创建一个函数,模仿写一个strlen函数
这里先用非递归方式
#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS
int my_strlen(char* str)
{int count = 0;while (*str != '\0'){count++;str++;}return count;
}int main(){char i[100];printf("请输入一个字符串: ");scanf("%s", i);my_strlen(i);printf(" %d", my_strlen(i));return 0;
}
count在这里只是起到一个计数器的作用
如果不太理解指针和数组,下面其辅助作用
int *p1 = &a;
int *p2 = &b;
int *p3 = &c;
int *p4 = &d;
arry[0] = &a;
arry[1] = &b;
arry[2] = &c;
arry[3] = &d;
下来试一下递归
如果第一个字符不是\0,那说明字符串里至少有一个字符
这就是我们的思路
****所以当第一个元素不是’\0’的话
求my_strlen(“abc”)就可以看成求1+my_strlen(“bc”)的长度
求1+my_strlen(“bc”)的长度就可以看成 求1+1+my_strlen(“c”)的长度
求1+1+my_strlen(“c”)的长度就可以看成 求1+1+1+my_strlen(" ")的长度,最后我们让my_strlen(“\0 ”)输出为零就行了
最后算出来等于3
首先写递归函数:
int my_strlen(char* str)
{if(*str !='\0'){return 1 + my_strlen(str+1);}else{return 0;}
}
递归过程如下

代码如下

递归与迭代
练习三
求n的阶乘的和
先构思好递归(思路如下,是别的博主的图,博主文章在前言)

代码实现
#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS
int my(int i)
{if(i<=1){return 1;}else{return i *my(i -1);}
}int main(){int i;printf("请输入一个数字: ");scanf("%d", &i);my(i);printf("%d", my(i));return 0;
}
但当数字变大时,递归会算不出结果

递归函数也只是一种解决问题的技巧,它和其它技巧一样,也存在某些缺陷,具体来说就是:递归函数的时间开销和内存开销都非常大,极端情况下会导致程序崩溃。
所以这道题最好用非递归的方式来计算,比如迭代,循环是一种迭代
练习四
求第N个斐波那契数列
什么是斐波那契数列

流程如下:

写出代码:
#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS
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);printf("%d",Fib(n));return 0;
}
在练习三、四中出现的问题
我们会出现这样的问题
-在使用 Fib 这个函数的时候如果我们要计算第50个斐波那契数字的时候特别耗费时间。
-使用my函数求10000的阶乘(不考虑结果的正确性),程序会崩溃。
原因是因
函数在调用过程中很多计算,其实一直在重复

系统分配给程序的栈空间是有限的,但是如果出现了死循环,或者(死递归),这样有可能导致一直开辟栈空间,最终产生栈空间耗尽的情况,这样的现象我们称为栈溢出
如何解决这个问题
1. 将递归改写成非递归。
2. 使用static全局静态对象替代 nonstatic 局部对象。在递归函数设计中,可以使用 static 对象替代nonstatic 局部对象(即栈对象),这不仅可以减少每次递归调用和返回时产生和释放 nonstatic 对象的开销,而且 static 对象还可以保存递归调用的中间状态,并且可为各个调用层所访问
————————————————
原文链接:https://blog.csdn.net/m0_68468727/article/details/126466506
#include<stdio.h>
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;
}int main()
{int n = 0;scanf("%d", &n);printf("%d\n", Fib(n));return 0;
}
提示
1. 许多问题是以递归的形式进行解释的,这只是因为它比非递归的形式更为清晰。
2. 但是这些问题的迭代实现往往比递归实现效率更高,虽然代码的可读性稍微差些。
3. 当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开销
如果您发现文章有错误请与我留言,感谢
相关文章:
再识C语言 DAY13 【递归函数(超详细)】
文章目录 前言一、函数递归什么是递归递归的两个重要条件练习一练习二 递归与迭代练习三练习四在练习三、四中出现的问题 如果您发现文章有错误请与我留言,感谢 前言 本文总结于此文章 一、函数递归 什么是递归 函数调用自身的编程技巧称为递归 (函数自…...
【Linux】权限管理
🔥博客主页: 小羊失眠啦. 🎥系列专栏:《C语言》 《数据结构》 《C》 《Linux》 《Cpolar》 ❤️感谢大家点赞👍收藏⭐评论✍️ 文章目录 一 、Linux中的用户1.1 Linux用户分类1.2 用户转换1.3 指令提权 二、Linux权限管…...
地理坐标系、空间坐标系、epsg查询网站
坐标系可用范围和详细信息的查询网站 简介 epsg.ruiduobao.com是一个可以查询gdal中所有坐标系信息的网站,可查询到坐标系的基准面、椭球体、中央子午线等相关信息,并对每个坐标系的可用范围在地图中进行了显示。详细信息可以看操作视频: e…...
docker 容器指定主机网段
docker 容器指定主机网段。 使用macvlan网络模式可以让Docker容器直接连接到物理网络,而不需要通过NAT或端口映射的方式来访问它们。可以提高网络性能和稳定性,同时也可以使容器更易于管理。 1、查询网卡的名称:使用ifconfig命令查看网卡名…...
零基础Vue框架上手;git,node,yarn安装
项目搭建环境: git安装:Git - 安装 Git (git-scm.com)(官网) 下载路径:Git - Downloading Package (git-scm.com);根据自己电脑下载相对应的安装包 点next 点next,点到最后安装就行。…...
十分钟学会用springboot制作微信小程序富文本编辑器
1.1 富文本模型设计 在构建富文本编辑器系统时,首先需要设计一个合适的富文本模型。 CREATE TABLE IF NOT EXISTS rich_texts (id INT PRIMARY KEY AUTO_INCREMENT,title VARCHAR(255),content TEXT,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );这个表包括…...
【BBF系列协议】TR181-1 TR069的设备数据模型
TR-069的TR-181设备数据模型 执行摘要 TR-181定义了TR-069 [2]设备数据模型的版本1(设备:1)。设备:1数据模型仅适用于启用TR-069的终端设备,不适用于互联网网关设备或其他网络基础设施设备。启用TR-069的基础设施设备改为使用TR-098 [4]互联网网关设备数据模型或未来设备…...
Elasticsearch(简称ES)性能优化 实践
Elasticsearch(简称ES)性能优化主要包括以下几个方面: 索引优化: 选择合适的分片数:根据业务需求和数据量合理设置分片数,避免过多或过少分片造成性能问题。分片数过多会导致创建分片速度变慢、集群易崩溃…...
《跨越阶层,小白选专业的逻辑:揭秘家庭背景与个人发展的秘密联系》
文章目录 底层最好的专业 小康最好的专业 中产最好的专业 巨富最好的专业 总结 一个人选专业选的好不好,不在于专业本身,而在于你的出身,你的起点,你的家庭;你需要读懂你的原生家庭的文化才能改变自己。换句话说就是&a…...
Python调用pyspark报错整理
前言 Pycharm配置了SSH服务器和Anaconda的python解释器,如果没有配置可参考 大数据单机学习环境搭建(8)Linux单节点Anaconda安装和Pycharm连接 Pycharm执行的脚本 执行如下 pyspark_model.py 的python脚本,构建SparkSession来执行sparksql "&qu…...
快递员的烦恼 - 华为OD统一考试
OD统一考试(C卷) 分值: 200分 题解: Java / Python / C 题目描述 快递公司每日早晨,给每位快递员推送需要淡到客户手中的快递以及路线信息,快递员自己又查找了一些客户与客户之间的路线距离信息࿰…...
css1基础选择器
大纲 一.标签选择器 比较简单,前面直接写目标标签 二.类选择器 应用 例子 三.多类名选择器(调用时中间用空格隔开) 四.id选择器 应用 五.通配符选择器 应用 六.总结...
【C语言】内联函数总结
内联函数定义 inline关键字是C99标准的型关键字,其作用是将函数展开,把函数的代码复制到每一个调用处。这样调用函数的过程就可以直接执行函数代码,而不发生跳转、压栈等一般性函数操作。可以节省时间,也会提高程序的执行速度。 …...
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之MenuItemGroup组件
鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之MenuItemGroup组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、MenuItemGroup组件 该组件用来展示菜单MenuItem的分组。 子组件 无 接…...
【Linux多线程编程】互斥锁及其使用
1、互斥锁 用于解决竞争问题的一种机制。 什么是竞争,竞争就是多个实体同时获取一个资源,例如多个线程写一个全局变量。 2、Linux如何使用互斥锁 以pthread为例,锁的创建和使用如下: /* 创建锁 */ pthread_mutex_t lock PTHR…...
RabbitMQ_00000
MQ的相关概念 RabbitMQ官网地址:https://www.rabbitmq.com RabbitMQ API地址:https://rabbitmq.github.io/rabbitmq-java-client/api/current/ 什么是MQ? MQ(message queue)本质是个队列,FIFO先入先出,只不过队列中…...
【linux】docker下homeassistant和nodered安装及配置
1、homeassistant安装 从 Docker Hub 上拉取 Home Assistant 的镜像文件 docker pull homeassistant/home-assistant 是运行 Home Assistant 容器 docker run -id --name"homeassistant" --privileged --restart always -p 8123:8123 -e TZAisa/Shanghai --nethost…...
Qt扩展-muParser数学公式解析
muParser数学公式解析 一、概述1. 针对速度进行了优化2. 支持的运算符3. 支持的函数4. 用户定义的常量5. 用户定义的变量6. 自定义值识别回调7. 其他功能 二、内置函数三、内置二元运算符四、三元运算符五、内置常量六、源码引入1. 源码文件2. 编译器开关1. MUP_BASETYPE2.MUP_…...
【Matplotlib】figure方法之图形的保存
🎈个人主页:甜美的江 🎉欢迎 👍点赞✍评论⭐收藏 🤗收录专栏:matplotlib 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进…...
数据库管理-第142期 DBA?DBA!(20240131)
数据库管理142期 2024-01-31 数据库管理-第142期 DBA?DBA!(20240131)正文总结 数据库管理-第142期 DBA?DBA!(20240131) 作者:胖头鱼的鱼缸(尹海文)…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
