C语言中的套娃——函数递归

目录

一、什么是递归

1.1.递归的思想

1.2.递归的限制条件

二、举例体会

2.1.求n的阶乘 

2.2.顺序打印整数的每一位

2.3.斐波那契数列

三、递归与迭代


一、什么是递归

在学习C语言的过程中,我们经常会跟递归打交道,什么是递归呢?它其实是一种解决问题的方法,递归递归,顾名思义,递推回归。在C语言中,函数自己调用自己就是递归,我们可以把它想成生活中的俄罗斯套娃。

下面请看最简单的递归代码:

#include <stdio.h>
int main()
{printf("hehe\n");main();//main函数中⼜调⽤了main函数return 0;
}

在上面的代码中,我们看到了main函数里再次调用了main函数,我们可以想象,这个程序会一直调用下去,直到,内存不够导致栈溢出(Stack overflow)。

1.1.递归的思想

递归的思想用一个词来讲就是“大事化小”。

其中代表递推代表回归。

1.2.递归的限制条件

刚刚我们看到,一直调用main函数的话,会造成死递归,因此,我们在使用递归时需要注意一些必要条件。

1.递归存在限制条件,当超过这个限制条件时递归就应该停止

2.每次递归应该越来越接近这个限制条件。 

接下来我们举几个例子来让大家体会一下这两个必要条件。

二、举例体会

2.1.求n的阶乘 

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

经分析可知n! = n * (n-1) * (n-2)... * 3 * 2 * 1,而(n-1)! = (n-1) * (n-2) *...* 3 * 2 * 1。

所以n! = n * (n-1)!。

我们要求n的阶乘,只需要求n和n-1的阶乘的乘积,问题也就变成了求n-1的阶乘。经过一次递归,我们就从n变到n-1,那递归的次数足够了,我们就可以到最后的1的阶乘。那怎么得到n的阶乘呢,我们刚刚一步一步得到1的阶乘,那我们再一步一步乘回去,最终得到n的阶乘。

上述思路就是所谓的递归,也就是把一个较大的问题转换为与原问题相似的小问题。

当n = 0时,n! = 1。我们可以得到递推公式:

代码如下:

函数部分

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

总体

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

测试结果

2.2.顺序打印整数的每一位

输入一个整数n,顺序打印其每一位。

input : 1234

output : 1 2 3 4

分析可知,1234/10 = 123,而1234%10 = 4。那我们可以巧妙的利用上述特性,得到1234的每一位。但是出现一个问题,我们获得的数字的顺序是倒着的,这该怎么办呢。我们可以仔细品味一下递归,递推和回归,先递推再回归。

我们就可以先进行/10的操作,再打印%10的余数,如下:

void Print(int n)
{if(n>9){Print(n/10);}printf("%d ", n%10);
}

画图推演一下:

代码如下:

#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.3.斐波那契数列

斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称“兔子数列”,其数值为:1、1、2、3、5、8、13、21、34…… 

其递推公式为

用递推写出代码很简单:

#include<stdio.h>int Fib(int n) 
{if (n == 1 || 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;
}

运行结果:

那如果让你不用递归的方法,你会怎么做呢? 

我们可以创建三个变量,就像两个数互相交换那样,将a赋值1,b赋值1,c为a与b的和。

n大于二之后才开始循环,所以我们可以这么写:

int Fib(int n) 
{int a = 1, b = 1,c = 0;while (n>2){c = a + b;a = b;b = c;n--;}return b;
}

 一个接着一个交换值,直到n等于2,退出循环,此时c的值赋给了b,而我们在n小于等于2的时候,求不出来c,而b的值正好是1,所以我们返回b的值。

三、递归与迭代

上面我们说了什么是递归,这又来个迭代,什么叫迭代呢?说白了通常就是循环。

比如刚才计算阶乘,我就不想用递归,那我就循环n次,也可以解决问题,并且该方法效率比递归高。

我们遇到的许多问题用递归解释的原因是因为,它比非递归好想好解释,但这些问题往往迭代比递归的效率更高。

我们说当一个问题非常复杂,难以用迭代的方式来解决时2,这时候递归实现的简洁性便可以补偿运行时的开销。

就像刚刚的例三,求斐波那契数列,使用迭代的方法就更加有效率。

如图所示,递归层次越深,冗余计算越多,我们可以简单测试一下

#include <stdio.h>
int count = 0;
int Fib(int n)
{if(n == 3)count++;//统计第3个斐波那契数被计算的次数if(n<=2)return 1;elsereturn Fib(n-1)+Fib(n-2);
}
int main()
{int n = 0;scanf("%d", &n);int ret = Fib(n);printf("%d\n", ret); printf("\ncount = %d\n", count);return 0;
}

 来看结果

这才是40,可想而知50会是多大的天文数字。

而迭代的方式,我们只需要前后一步一步相加即可。


最后总结一下,递归是一个很好的解决问题方式,在编程学习中,我们会经常用到它,但是它也不是万能的,还是需要我们多动脑思考。

我相信,我们总会找到解决办法的。

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

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

相关文章

LNMP 架构

环境准备&#xff1a;lnmp 需要安装 nginx mysql php 论坛/博客 软件 使用LNMP架构搭建 论坛 1. 关闭防火墙和和核心防护 systemctl disable --now firewalld setenforce 0 2. 编译安装 nginx 安装依赖包 yum -y install pcre-devel zlib-devel gcc gcc-c make 创建…

Compiling from source on UNIX(cmake doxygen ant maven ccache)

前言 源码链接 cmake-3.18.0 https://cmake.org/files/v3.18/cmake-3.18.0.tar.gzdoxygen-1.10.0 https://www.doxygen.nl/files/doxygen-1.10.0.src.tar.gzapache-ant-1.10.8-bin https://archive.apache.org/dist/ant/binaries/apache-ant-1.10.8-bin.tar.gzapache-maven-3…

#WEB前端(表单)

1.实验&#xff1a; form、input、label 登录界面&#xff0c;表单填写界面 2.IDE&#xff1a;VSCODE 3.记录&#xff1a; 4.代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name&q…

RedisTemplate中opaForValue.set的注意之处

问题 原本写了一个小项目&#xff0c;想通过redis缓存实现登录退出功能&#xff0c;结果出现了莫名奇妙的问题 代码如下&#xff1a; 报错&#xff1a; 经过多次调试之后我发现是opsForValue.set(key,value,expireTime)这行代码的问题&#xff0c;没有指定过期时间的单位&…

备战蓝桥杯---动态规划之悬线法

Em...属于一知道就会&#xff0c;不知道的话比较难想。 我们先看题&#xff1a; 我们不妨把1抽象成一个平面上的点&#xff0c;因此可以变成这一幅图&#xff1a; 我们假设每一个点被向上牵拉了一根线&#xff1a; 显然&#xff0c;每一条悬线都有可能成为边界限制&#xff0c…

Bulingbuling - 《历史的教训》 [ The Lessons of History ]

《历史的教训》 两位当代最伟大思想家的著名论文集&#xff0c;汇集了 5000 多年的历史 作者&#xff1a;威尔-杜兰特和阿里尔-杜兰特 The Lessons of History The celebrated collection of essays compiling over 5,000 years of history by two of the greatest thinkers …

Spring Boot项目中不使用@RequestMapping相关注解,如何动态发布自定义URL路径

一、前言 在Spring Boot项目开发过程中&#xff0c;对于接口API发布URL访问路径&#xff0c;一般都是在类上标识RestController或者Controller注解&#xff0c;然后在方法上标识RequestMapping相关注解&#xff0c;比如&#xff1a;PostMapping、GetMapping注解&#xff0c;通…

Siamrpn++论文中文翻译(详细!)

SiamRPN: Evolution of Siamese Visual Tracking with Very Deep Networks SiamRPN&#xff1a;具有非常深度网络的Siamese视觉跟踪的进化 【siamrpn论文地址】 https://arxiv.org/abs/1812.11703 摘要 基于Siamese网络的跟踪器将跟踪表示为目标模板和搜索区域之间的卷积特征…

【STA】多场景时序检查学习记录

单周期路径 建立时间时序检查 在时钟的有效沿到达触发器之前&#xff0c;数据应在一定时间内保持稳定&#xff0c;这段时间即触发器的建立 时间。满足建立时间要求将确保数据可靠地被捕获到触发器中。 建立时间检查是从发起触发器中时钟的第一个有效沿到捕获触发器中时钟后面…

基于springboot+vue的社区医院管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

chatgpt-3的文章生成器有哪些?可以批量生成文章的生成器

GPT-3&#xff08;Generative Pre-trained Transformer 3&#xff09;作为人工智能领域的一项重大突破&#xff0c;开启了新一代的文本生成技术。同时市面上也涌现出了一些GPT-3文章生成器&#xff0c;为用户提供了快速、高效地生成各种类型文章的工具。本文将介绍一些中国的GP…

python笔记_程序流程控制

A&#xff0c;顺序控制 程序从上到下逐行执行 python定义变量时&#xff0c;会合法地向前引用 age 1 age2 age 1 age2 age 1 age 1 ——>错误&#xff0c;age应在age2之前 B&#xff0c;分支控制 1&#xff0c;单分支if 语法 if 条件表达式 &#xff1a; 代码块 说明…

数字化转型导师坚鹏:证券公司数字化思维升级之道

证券公司数字化思维升级之道 ——数字化思维之六脉神剑 课程背景&#xff1a; 很多证券公司存在以下问题&#xff1a; 不知道数字化转型如何改变思维模式&#xff1f; 不清楚需要建立什么样的数字化思维&#xff1f; 不知道如何开展数字化思维提升工作&#xff1f; 课…

Redis之十:Spring Data Redis --- CrudRepository方式

SpringData Redis CrudRepository方式 Spring Data Redis 的 CrudRepository 是 Spring Data 框架中用于提供基础 CRUD&#xff08;创建、读取、更新和删除&#xff09;操作的一个接口。在与 Redis 集成时&#xff0c;尽管 Redis 是一个键值存储系统&#xff0c;并没有像关系型…

关于福彩历史数据采集器和体彩历史数据采集器的下载安装说明

前段时间因为研究基于人工神经网络&#xff08;深度学习&#xff0c;所谓的“AI”算法&#xff09;对3D开奖数据进行预测&#xff0c;开发了两款浏览器插件----“福彩历史数据采集器”和“体彩历史数据采集器”。之所以开发这两款插件&#xff0c;是因为不管是基于什么样的方式…

【QT+QGIS跨平台编译】之六十三:【QGIS_CORE跨平台编译】—【错误处理:未定义的类QgsMapLayer - QgsMapLayerModel】

文章目录 一、未定义的类QgsMapLayer二、解决办法 一、未定义的类QgsMapLayer 报错&#xff1a; 二、解决办法 QgsMapLayerModel.h文件中 ①第27行修改为&#xff1a; #include "QgsMapLayer.h" ②第23行增加&#xff1a; #include <QPointer>

Github 2024-03-03 开源项目日报Top9

根据Github Trendings的统计&#xff0c;今日(2024-03-03统计)共有9个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量非开发语言项目4Rust项目1C项目1Jupyter Notebook项目1Python项目1Shell项目1 任天堂Switch模拟器yuzu&#x…

编写dockerfile挂载卷

编写dockerfile文件 [rootwq docker-test-volume]# vim dockerfile1 [rootwq docker-test-volume]# cat dockerfile1 FROM centosVOLUME ["volume01","volume02"]CMD echo "------end------" CMD /bin/bash [rootwq docker-test-volume]#使用do…

leetcode:51.N皇后(复习)

题目理解&#xff1a;&#xff08;回溯算法&#xff09; 树形结构——层数代表行数&#xff0c;递归的深度就是总行数。 代码实现&#xff1a;

手写 Attention 迷你LLaMa2——LLM实战

https://github.com/Yuezhengrong/Implement-Attention-TinyLLaMa-from-scratch 1. Attention 1.1 Attention 灵魂10问 你怎么理解Attention&#xff1f; Scaled Dot-Product Attention中的Scaled&#xff1a; 1 d k \frac{1}{\sqrt{d_k}} dk​ ​1​ 的目的是调节内积&…