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

文章目录

  • 一、什么是递归?
    • 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,在函数递归的时候我们要逐渐的接近这个递归条件。
当然函数递归的学习远不如于此,需要大家在不断的实践练习中不断了解函数递归的妙用。这是小编对于函数递归的理解如果有读者有看不懂的地方或者更好的建议欢迎评论下方留言。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

配置Java开发环境

Java是一种广泛使用的编程语言&#xff0c;特别是在企业应用和安卓开发中。本文将详细介绍如何在您的计算机上配置Java开发环境&#xff0c;包括安装JDK、配置环境变量以及选择和设置IDE。 一、安装Java Development Kit (JDK) JDK&#xff08;Java Development Kit&#xff0…

IDEA阿里云OSS实现文件上传·解决苍穹外卖图片回显

简单交代配置阿里云OSS的思路 1. 首先去阿里云开通一个OSS服务&#xff0c;配置好一个自己的Bucket 2. 在IDEA配置Bucket 3. 拷贝官网的OSS工具类代码 package com.sky.utils;import com.aliyun.oss.ClientException; import com.aliyun.oss.OSS; import com.aliyun.oss.OSS…

Redis 配置与优化

一、关系型数据库与非关系型数据库 &#xff08;一&#xff09;关系型数据库 关系型数据库是结构化数据库&#xff0c;创建在关系型模型数据库&#xff0c;创建面向于记录。 常见的关系型数据库&#xff1a;Oracle、MySQL、SQL Server、Microsoft Access、DB2。 &#xf…

2024年浙江省高考分数一分一段数据可视化

下图根据 2024 年浙江高考一分一段表绘制&#xff0c;可以看到&#xff0c;竞争最激烈的分数区间在620分到480分之间。 不过&#xff0c;浙江是考两次取最大&#xff0c;不是很有代表性。看看湖北的数据&#xff0c;580分到400分的区段都很卷。另外&#xff0c;从这个图也可以…

【vue】下载 打印 pdf (问题总结)- 持续更新ing

这里是目录标题 一、pdf1.查看 下载一、pdf 1.查看 下载 样式 Code<template><div><el-table :data="pdfList" style="width: 100%" border ><el-table-columnprop="index"label="序号"width="80"ali…

告别低效地推!Xinstall助力,一键生成专属渠道二维码

在移动互联网时代&#xff0c;地推作为一种传统而有效的推广方式&#xff0c;依然被众多企业所青睐。然而&#xff0c;传统的地推方式往往伴随着繁琐的填码、人工登记以及难以追踪的下载来源等问题&#xff0c;极大地降低了推广效率。为了解决这些痛点&#xff0c;Xinstall应运…

5,智能合约(react+区块链实战)

5&#xff0c;智能合约&#xff08;react区块链实战&#xff09; 5-1 智能合约5-2 metamask安装及私有链搭建互相联动5-3 solidity数据类型-布尔-数字-地址&#xff08;owner区别&#xff09;5-4 solidity 数组和映射&#xff08;代币转账&#xff09;5-5 solidity结构体与枚举…

AI虚拟医生重塑医患关系

如今&#xff0c;越来越多的企业开始选择用AI虚拟数字人播报员替代真人出镜&#xff0c;这不仅有助于企业实现降本增效的目标&#xff0c;更能让广告传播趋向多样化和个性化。对于普通人而言&#xff0c;也摆脱了真人出镜的种种烦恼&#xff0c;让表达更加自由与便捷。AI虚拟数…

视频太大怎么压缩变小?这几种压缩方法值得收藏!

视频太大怎么压缩变小&#xff1f;在数字化浪潮汹涌的时代&#xff0c;处理大型视频文件已不再仅仅是存储空间的挑战&#xff0c;我们身处于数据洪流之中&#xff0c;数据的安全与隐私的保护已然成为了我们不得不面对的重大议题&#xff0c;特别是随着视频内容的井喷式增长及其…

怎么提高音频的播放速度?可以提高音频播放速度的四种方法推荐

怎么提高音频的播放速度&#xff1f;提高音频的播放速度是一种有效的策略&#xff0c;可以显著节省时间和提升信息获取的效率。随着信息量不断增加和学习需求的多样化&#xff0c;快速播放音频已成为许多人在日常生活和工作中的常见做法。这种方法不仅可以用于提高学习效率&…

医院人员管理系统03_下午:C3P0连接池,完成简单的增删改查

文章目录 什么是C3P0项目目录Students.javaC3P0Conn.javaStuDao.java套路代码 什么是C3P0 C3P0连接池要比jdbc更简单&#xff0c;dao层写方法就能看出来 项目目录 Students.java 没有变&#xff0c;直接是jdbc的实体类 跳转我的上一篇文章查看实体类代码 C3P0Conn.java 这…

Elasticsearch:Node.js ECS 日志记录 - Winston

这是继上一篇文章 “Elasticsearch&#xff1a;Node.js ECS 日志记录 - Pino” 的续篇。我们继续上一篇文章来讲述使用 Winston 包来针对 Node.js 应用生成 ECS 向匹配的日子。此 Node.js 软件包为 winston 记录器提供了格式化程序&#xff0c;与 Elastic Common Schema (ECS) …

一键掌握天气动态 - 基于Vue和高德API的实时天气查询

前言 本文将学习如何使用Vue.js快速搭建天气预报界面,了解如何调用高德地图API获取所需的天气数据,并掌握如何将两者有机结合,实现一个功能丰富、体验出色的天气预报应用 无论您是前端新手还是有一定经验,相信这篇教程都能为您带来收获。让我们一起开始这段精彩的Vue.js 高德…

音视频开发—FFmpeg 从MP4文件中抽取视频H264数据

文章目录 MP4文件存放H264数据方式MP4 文件结构概述H.264 数据在 MP4 中的存储1. ftyp 盒子2. moov 盒子3. mdat 盒子 H.264 数据在 stsd 盒子中的存储&#xff08;AVC1&#xff09;AVC1与Annex-B 格式&#xff08;裸 H.264 流&#xff09;的区别 从MP4文件中提取H264裸流步骤&…

zynq启动和程序固化流程

普通FPGA启动 FPGA的启动方式主要包含主动模式、被动模式和JTAG模式。 主动模式&#xff08;AS模式&#xff09; 当FPGA器件上电时&#xff0c;它作为控制器从配置器件EPCS中主动发出读取数据信号&#xff0c;并将EPCS的数据读入到自身中&#xff0c;实现对FPGA的编程。这种…

石油巨头受冲击!埃克森美孚、BP接连发出盈利预警

KlipC报道&#xff1a;近日&#xff0c;BP&#xff08;英国石油&#xff09;预计其第二季度将面临10亿至20亿美元的减值费用&#xff0c;并发出警告称其炼油利润率“大幅下降”&#xff0c;石油交易收益预计出现疲软。消息公布后&#xff0c;其股价下跌超4%。 由于中间馏分油利…

【三维重建】【深度学习】windows11下3DGS代码Pytorch实现

【三维重建】【深度学习】windows11下3DGS代码Pytorch实现 提示:最近开始在【三维重建】方面进行研究,记录相关知识点,分享学习中遇到的问题已经解决的方法。 文章目录 【三维重建】【深度学习】windows11下3DGS代码Pytorch实现前言3DGS模型运行安装CUDA安装 Visual Studio C编…

PlugLink的技术架构实例解析(附源码)

在探讨PlugLink这一开源应用的实际应用与技术细节时&#xff0c;我们可以从其构建的几个核心方面入手&#xff0c;结合当前AI编程的发展趋势&#xff0c;为您提供既有实例又有深度解析的内容。 PlugLink的技术架构实例解析 前端技术选型 —— layui框架&#xff1a; PlugLi…

最新 Kubernetes 集群部署 + Contranerd容器运行时 + flannel 网络插件(保姆级教程,最新 K8S 1.28.2 版本)

资源列表 操作系统配置主机名IP所需插件CentOS 7.92C4Gk8s-master192.168.60.143flannel-cni-plugin、flannel、coredns、etcd、kube-apiserver、kube-controller-manager、kube-proxy、 kube-scheduler 、containerd、pause 、crictlCentOS 7.92C4Gk8s-node01192.168.60.144f…

Cadence23 中 Capture 与 PCB Editor 的交互

1.Capture选中器件在PCB Editor 中高亮显示 1.点击N的图标选项卡&#xff0c;导出第一网表 2,导入第一网表&#xff1a; 点击移动命令&#xff0c;在查找选项卡中选择Symbol器件选项卡&#xff1a; 点击器件即可高亮&#xff1a; 2.PCB Editor选中器件在 Capture中高亮显示 …