【C语言】函数递归 (包你懂的)

news2024/11/27 20:39:40

文章目录

  • 1. 前言
  • 2. 递归的定义
    • 2.1 递归的思想
    • 2.2 递归的限制条件
  • 3. 递归举例
    • 3.1 举例1:求n的阶乘
      • 3.1.1 分析和代码实现
      • 3.1.2 画图演示
    • 3.2 举例2:顺序打印一个整数的每一位
      • 3.2.1 分析和代码实现
      • 3.2.3 画图演示
    • 3.3 举例3:求第n个斐波那契数
      • 3.3.1 分析和代码实现
  • 4. 总结

1. 前言

在我们了解清楚函数的知识点后,我们还得认识一下函数递归。学好函数递归,也是在为我们后期提高自己代码编程的能力奠定基础。

那么,现在是侦破时间!!!

2. 递归的定义

递归其实是解决问题的一种方法,等到大家后面在学习数据算法与结构的时候还会遇见它。
递归说白了就是函数自己调用自己

现在我们写一个史上最简单的C语言递归代码:

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

上述就是一个简单的递归程序,只是为了演示递归的基本形式,不做它用。而上述的这个代码最终会陷入死递归,导致栈溢出(Stack overflow)。

栈溢出

2.1 递归的思想

这个知识点十分重要,也是我们在使用递归时的基本思想和思路方向。

把一个大型复杂的问题拆解成一个与原问题相似,当规模较小的子问题来解决。直至子问题不能再被拆分了,递归就结束了。如果子问题能够被一直拆分,停不下来,就会出现开头我们讲的死递归,也就是栈溢出现象。

总的来说,递归的思考方式就是把大事化小的过程。(这句话请牢记)

递归可以拆成两个字“递”和“归”。其中递”就是递推的意思,“归”就是回归的意思。如果还没理解,不用担心,接下来我们一起慢慢体会。

2.2 递归的限制条件

不敢想象,当一个函数无穷无尽的递归下去,会对计算机的内存造成多大的心理创伤。
为了保护我们内存宝宝这颗敏感易碎的心灵,我们得给函数递归加以限制,让它达到某种我们希望的程度时就停止下来,然后得到我们想要的结果。
所以,函数的递归时必不可少的!

那我们该怎么写递归的限制条件呢?

递归在书写的时候,有2个必要条件:

  • 递归存在限制条件,当满足这个限制条件时,函数递归就不再进行下去。
  • 每次递归调用之后越来越接近这个限制条件。

在下面的例子中,我们来逐步感受这两句话的魅力所在。

3. 递归举例

3.1 举例1:求n的阶乘

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

3.1.1 分析和代码实现

拆解思路
那这里就会有一个问题,这个阶乘到底能藏得了多久?
仔细思考,阶乘无非就是从自然数开始算起,而0的阶乘我们规定是1。因此,这个阶乘最多只能藏到0这个数字。

下面,总结以上思路,我给大家列出了这么一个公式:
阶乘的递归公式

那我们就可以写出函数Fact求n的阶乘,假设Fact(n)就是求n的阶乘,那么Fact(n-1)就是求n-1的阶乘,函数如下:

int Fact(int n)
{
	if(n == 0) //n==0就是函数递归的限制条件
	{
		return 1;
	}
	else
	{
		return n*Fact(n-1); //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;
}

阶乘的函数递归完整代码

3.1.2 画图演示

图解
相信看完这幅图后,你对递归是如何运作的理解有更深一层了。

3.2 举例2:顺序打印一个整数的每一位

真热打铁,接着来!!!

题目:输入一个整数,按照顺序打印整数的每一位

3.2.1 分析和代码实现

首先看到这道题目,我们就会先想该如何将整数的每一位先弄出来,之后再打印。其实把整数每一位都弄出来不难,思路如下:

如果n是一位数,n的每一位就是n自己
n是超过1位数的话,就得拆分每一位
比如:现在n=1234,那么我们可以这么做:

先1234%10,可以得到个位数上的4;接着再将1234/10的结果重新赋值给n,此时n的值就为123(1234/10这步操作就相当于把4给除掉了)。然后继续对123%10,得到3,再除10去掉3,以此类推。
但是这里有个问题,这样做的话,我们打印出来的数字顺序是倒着的。

但是我们有了灵感,我们发现其实⼀个数字的最低位是最容易得到的,通过%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
完成上述的步骤,那就完成了1234每一位的打印

那么Print(123)⼜可以拆分为Print(123/10) + printf(123%10)

以此类推,就有:
思路

那么完成代码也就比较清楚:

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.2.3 画图演示

画图展示

3.3 举例3:求第n个斐波那契数

什么是斐波那契数列?

斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N)

3.3.1 分析和代码实现

不难发现,从第三个数开始,每个数都是前两个数的和

2 = 1+1
3 = 2+1
5 = 3+2

看到这里,我想你的DNA已经开始躁动了。这不就可以用递归实现。

代码实现:

#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);
	int ret = Fib(n);
	printf("%d\n",ret);
	return 0;
}

结果展示

限于篇幅问题,这里就不再带着大家画图了,感兴趣的读者下来可以自己动手把这个问题的图给画出来。后期我还会出关于斐波那契数列的文章。希望大家多多关注。

4. 总结

在本文中,详细的讲解了什么是递归、递归的核心思想以及如何用递归解决问题。

创作不易,希望大家不要吝啬手中的点赞,感谢大家的支持。❤️❤️❤️

学习很难,但坚持一定很酷!!!😎😎😎 加油!

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

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

相关文章

Unity动画录制工具在运行时录制和保存模型骨骼运动的方法录制动画给其他角色模型使用支持JSON、FBX等格式

如果您正在寻找一种在运行时录制和保存模型骨骼运动的方法&#xff0c;那么此插件是满足您需求的完美解决方案。 实时录制角色运动 将录制到的角色动作转为动画文件 将录制好的动作给新的角色模型使用&#xff0c;完美复制 支持导出FBX格式 操作简单&#xff0c;有按钮界面…

【原创】springboot+mysql村务档案管理系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…

MySQL数据库操作基础(增删查改)

数据库操作基础(增删查改) 1.插入 1.1往数据表中插入一条数据 insert into 表名 values (值,值,值...)此处列出的这些值的数目和类型 要和表的相对应 1.2指定列插入 insert into 表名(列名) values (值);1.3一次插入多个记录 insert into 表名 values (值),(值)...一次插入…

深度学习500问——Chapter10:迁移学习(1)

文章目录 11.1 迁移学习基础知识 11.1.1 什么是迁移学习 11.1.2 为什么需要迁移学习 11.1.3 迁移学习的基本问题有哪些 11.1.4 迁移学习有哪些常用概念 11.1.5 迁移学习与传统机器学习有什么区别 11.1.6 迁移学习的核心及度量准则 11.1.7 迁移学习与其他概念的区别 11.1.8 什么…

达梦数据库相关SQL及适配Mysql配置总结

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

Leetcode 力扣109. 有序链表转换二叉搜索树 (抖音号:708231408)

给定一个单链表的头节点 head &#xff0c;其中的元素 按升序排序 &#xff0c;将其转换为 平衡 二叉搜索树。 示例 1: 输入: head [-10,-3,0,5,9] 输出: [0,-3,9,-10,null,5] 解释: 一个可能的答案是[0&#xff0c;-3,9&#xff0c;-10,null,5]&#xff0c;它表示所示的高…

每日一题——Python实现PAT乙级1042 字符统计(举一反三+思想解读+逐步优化)

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 优点 缺点和改进建议 时间复杂度分析 空间复杂度分析 改进后的代码 我…

关键字、保留字、标识符

关键字 关键字是被 Java 赋予了特定含义的英文单词。 关键字的字母全部小写。 保留字 现有的 Java 版本尚未使用&#xff0c;但是以后版本可能会作为关键字使用。自己命名标识符时需要避免使用这些保留字。 保留字有&#xff1a;byValue, cast, future, generic, inner, op…

数据并非都是正态分布:三种常见的统计分布及其应用

你有没有过这样的经历&#xff1f;使用一款减肥app&#xff0c;通过它的图表来监控自己的体重变化&#xff0c;并预测何时能达到理想体重。这款app预测我需要八年时间才能恢复到大学时的体重&#xff0c;这种不切实际的预测是因为应用使用了简单的线性模型来进行体重预测。这个…

【吊打面试官系列-Mysql面试题】BLOB 和 TEXT 有什么区别 ?

大家好&#xff0c;我是锋哥。今天分享关于 【BLOB 和 TEXT 有什么区别&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; BLOB 和 TEXT 有什么区别 &#xff1f; BLOB 是一个二进制对象&#xff0c;可以容纳可变数量的数据。TEXT 是一个不区分大小写的 BLOB。 1…

Java 语言概述 -- Java 语言的介绍、现在、过去与将来

大家好&#xff0c;我是栗筝i&#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 001 篇文章&#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验&#xff0c;并希望进…

使用proteus仿真51单片机的流水灯实现

proteus介绍&#xff1a; proteus是一个十分便捷的用于电路仿真的软件&#xff0c;可以用于实现电路的设计、仿真、调试等。并且可以在对应的代码编辑区域&#xff0c;使用代码实现电路功能的仿真。 汇编语言介绍&#xff1a; 百度百科介绍如下&#xff1a; 汇编语言是培养…

Knife4j 生成 API 文档

文章目录 Knife4j 简介使用步骤Knife4j 常用注解的列表案例注意 Knife4j 简介 Knife4j 是一个增强的 Swagger 文档生成工具&#xff0c;提供了更加友好的界面和更多功能&#xff0c;使得 API 文档更加美观且易于使用。它是基于 Spring Boot 和 Swagger 进行封装的&#xff0c;…

【下篇】从 YOLOv1 到 YOLOv8 的 YOLO 物体检测模型历史

YOLO 型号之所以闻名遐迩,主要有两个原因:其速度和准确性令人印象深刻,而且能够快速、可靠地检测图像中的物体。上回我解释了YoloX, 今天从Yolov6开始。 YOLOv6:面向工业应用的单级物体检测框架 美团视觉人工智能事业部(Meituan Vision AI Department)于 2022 年 9 月在…

《精通ChatGPT:从入门到大师的Prompt指南》第4章:避免常见错误

第4章&#xff1a;避免常见错误 在使用ChatGPT进行Prompt编写时&#xff0c;常见的错误可能会大大影响生成内容的质量和准确性。本章将详细讨论这些错误&#xff0c;并提供如何避免它们的建议。 4.1 不明确的指令 在使用ChatGPT时&#xff0c;一个常见的问题是指令不够明确。…

Vue3中的常见组件通信之$attrs

Vue3中的常见组件通信之$attrs 概述 ​ 在vue3中常见的组件通信有props、mitt、v-model、 r e f s 、 refs、 refs、parent、provide、inject、pinia、slot等。不同的组件关系用不同的传递方式。常见的撘配形式如下表所示。 组件关系传递方式父传子1. props2. v-model3. $re…

LLVM Cpu0 新后端4

想好好熟悉一下llvm开发一个新后端都要干什么&#xff0c;于是参考了老师的系列文章&#xff1a; LLVM 后端实践笔记 代码在这里&#xff08;还没来得及准备&#xff0c;先用网盘暂存一下&#xff09;&#xff1a; 链接: https://pan.baidu.com/s/1V_tZkt9uvxo5bnUufhMQ_Q?…

动态规划学习(分组背包)

分组背包的定义 分组背包是相比于01背包来讲&#xff0c;其就是多了一个组&#xff0c;给你n个组&#xff0c;每个组里有各自的物品&#xff0c;每个组里的物品只能选择一个&#xff0c;问你&#xff0c;选出来的最大价值是多少 这里我们的遍历顺序的三层循环&#xff0c;最外…

Burp Suite Professional 2024.5 (macOS, Linux, Windows) - Web 应用安全、测试和扫描

Burp Suite Professional 2024.5 (macOS, Linux, Windows) - Web 应用安全、测试和扫描 Burp Suite Professional, Test, find, and exploit vulnerabilities. 请访问原文链接&#xff1a;Burp Suite Professional 2024.5 (macOS, Linux, Windows) - Web 应用安全、测试和扫描…

Spring boot+vue前后端分离

目录 1、前端vue的搭建 2、后端项目的构建 pom文件中引入的jar包 yml文件用来配置连接数据库和端口的设置 application.property进行一些整合 service层 imp层 mapper 实体类 额外写一个类、解决跨域问题 3、测试 1、前端vue的搭建 建立项目的过程略 开启一个建立好…