再识C语言 DAY13 【递归函数(超详细)】

news2024/9/21 18:59:46

文章目录

  • 前言
  • 一、函数递归
    • 什么是递归
    • 递归的两个重要条件
    • 练习一
    • 练习二
  • ==递归与迭代==
    • 练习三
    • 练习四
    • ==在练习三、四中出现的问题==
  • 如果您发现文章有错误请与我留言,感谢


前言

本文总结于此文章


一、函数递归

什么是递归

函数调用自身的编程技巧称为递归
函数自己调用自己
递归分为**递推和回归**
递归的策略
它通常把一个大型复杂的问题层层转换为一个与原问题相似的小问题来解决。
递归的重要思想:把大事化小

例如(史上最简单的递归):

#include<stdio.h>
int main()
{
	printf("Hello World\n");
	main();
}

先一直打印 Hallo World,最终程序挂掉

在这里插入图片描述

递归的两个重要条件

因当存在限制条件,当满足这个限制条件时递归便不再继续。
每次递归调用之后越来越接近这个限制条件。

练习一

接受一个整型值(无符号),按顺序打印他的每一位
例如:
输入:1234,输出 1 2 3 4

我们的第一想法就是:

	1234%10 = 4
	1234/10=123
	123%10=3
	123/10=12
	12%10=2
	12/10=1
	1%10=1
	1/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", &amp;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. 当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开销


如果您发现文章有错误请与我留言,感谢

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

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

相关文章

【机器学习】全网最全模型评价指标(性能指标、YOLOv5训练结果分析、轻量化指标、混淆矩阵详解)【基础收藏】

&#x1f951; Welcome to Aedream同学 s blog! &#x1f951; 文章目录 模型性能指标常见指标ROC/AUCROC & PRC多分类问题——混淆矩阵 计算结果分析——以YOLO v5为例1. confusion_matrix.png(混淆矩阵)2. F1_curve&#xff1a;3. labels.jpg4. labels_corrrelogram.jpg5…

STM32外部中断(红外传感器与旋转编码器计数案例)

文章目录 一、介绍部分简介中断系统中断执行流程STM32中断NVIC基本结构NVIC优先级分组外部中断外部中断简介外部中断基本结构外部中断的流程AFIOEXTI框图 相关外设介绍旋转编码器介绍硬件电路对射式红外传感器 二、代码实现对射式红外传感器计次连接电路封装红外传感器与中断函…

清华系2B模型杀出,性能吊打LLaMA-13B

2 月 1 日&#xff0c;面壁智能与清华大学自然语言处理实验室共同开源了系列端侧语言大模型 MiniCPM&#xff0c;主体语言模型 MiniCPM-2B 仅有 24 亿&#xff08;2.4B&#xff09;的非词嵌入参数量。 在综合性榜单上与 Mistral-7B 相近&#xff0c;在中文、数学、代码能力表现…

怎么把物品信息图片批量生成二维码?每张图片单独生码的制作技巧

现在通过扫码来查看人员或者物品信息的方式越来越常见&#xff0c;在合适的位置放置对应的二维码内容&#xff0c;让其他人通过扫码来获取图片信息。那么如果我们将每个信息做成一张图片后&#xff0c;需要将图片生成二维码时&#xff0c;有能够批量生成二维码的方法可以快速处…

天地伟业接入视频汇聚/云存储平台EasyCVR详细步骤

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

基于深度卷积神经网络的图像配准(DeepSlice)

文章目录 一、基于DeepSlice的切片配准1.1、研究现状1.2、网络模型&#xff08;DeepSlice&#xff09;1.3、优化策略1.3.1、开发了一个基准数据集&#xff08;GT&#xff09;1.3.2、构建了阶段二的训练数据集&#xff08;增强训练&#xff09;1.3.3、角度集成 切割索引&#x…

[ChatGPT们】ChatGPT 如何辅助编程初探

主页&#xff1a;元存储的博客 全文 9000 字&#xff0c; 原创请勿转载。 我没有写过诗&#xff0c;但有人说我的代码像诗一样优雅 -- 雷军 图片来源&#xff1a;https://www.bilibili.com/video/BV1zL411X7oS/ 1. 引言 作为一个程序员&#xff0c;我们不仅要熟悉各种编程语…

ctfshow web入门 1-2 +密码签到

web1 F12源代码 web2 ctrlu cypto 签到 a}wohs.ftc{galf print(a[::-1])

使用 LoRA 在 vi​​ggo 数据集上微调 Microsoft phi-2 小语言模型

一、说明 Microsoft 的基于 Transformer 的小语言模型。它可以根据 MIT 许可在HuggingFace上使用。 它在 96 个 A100 GPU 上使用 1.4T 令牌进行了 14 天的训练。Phi-2 是一个 27 亿个参数的预训练 Transformer&#xff0c;不使用 RLHF 或指示微调。它进行下一个标记预测&#x…

RNN(神经网络)

目录 介绍&#xff1a; 数据&#xff1a; 模型&#xff1a; 预测&#xff1a; 介绍&#xff1a; RNN&#xff0c;全称为循环神经网络&#xff08;Recurrent Neural Network&#xff09;&#xff0c;是一种深度学习模型&#xff0c;它主要用于处理和分析序列数据。与传统…

Python入门:生成器迭代器

一、列表生成式 现在有个需求&#xff0c;列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]&#xff0c;要求你把列表里的每个值加1&#xff0c;怎么实现&#xff1f;你可能会想到2种方式 二逼青年版 1 2 3 4 a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] b [] for i in a:b.append(i1) print(b) …

如果通过浏览器调试?

背景&#xff1a;博主是一个有丰富经验的后端开发人员&#xff0c;在前端开发中感觉总是有种力不从心的感觉&#xff0c;因为没有后端debug调试的清晰感。 解决办法&#xff1a;掌握chorm浏览器调试技巧。 F12&#xff0c; F5 打上断点之后&#xff0c;这不就是梦寐之中的调试…

Linux驱动 SPI子系统

1、SPI协议 SPI&#xff08;Serial Peripheral Interface&#xff09;是一种同步串行数据通信协议&#xff0c;通常用于连接微控制器和外部设备&#xff0c;如传感器、存储器、显示器等。SPI协议使用四根线进行通信&#xff0c;包括时钟线&#xff08;SCLK&#xff09;、数据输…

第十二篇【传奇开心果系列】Python的OpenCV技术点案例示例:视频流处理

传奇开心果短博文系列 系列短博文目录Python的OpenCV技术点案例示例短博文系列短博文目录一、前言二、视频流处理介绍三、实时视频流处理示例代码四、视频流分析示例代码五、归纳总结系列短博文目录 Python的OpenCV技术点案例示例短博文系列 短博文目录 一、前言 OpenCV视频…

【面试官问】Redis 持久化

目录 【面试官问】Redis 持久化 Redis 持久化的方式RDB(Redis DataBase)AOF(Append Only File)混合持久化:RDB + AOF 混合方式的持久化持久化最佳方式控制持久化开关主从部署使用混合持久化使用配置更高的机器参考文章所属专区

OfficeWeb365 Readfile 任意文件读取漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

Qt|实现时间选择小功能

在软件开发过程中&#xff0c;QtDesigner系统给出的控件很多时候都无法满足炫酷的效果&#xff0c;前一段时间需要用Qt实现选择时间的小功能&#xff0c;今天为大家分享一下&#xff01; 首先看一下时间效果吧&#xff01; 如果有需要继续往下看下去哟~ 功能 1&#xff1a;开…

池化技术的总结

文章目录 1.什么是池化技术2.池化技术的应用一、连接池二、线程池三、内存池 3.池化技术的总结 1.什么是池化技术 池化技术指的是提前准备一些资源&#xff0c;在需要时可以重复使用这些预先准备的资源。 在系统开发过程中&#xff0c;我们经常会用到池化技术。通俗的讲&am…

xlsx xlsx-style 使用和坑记录

1 安装之后报错 npm install xlsx --savenpm install xlsx-style --save Umi运行会报错 自己代码 import XLSX from "xlsx"; import XLSXStyle from "xlsx-style";const data [["demo1","demo2","demo3","demo4&quo…

电路设计(9)——八路智力抢答器的proteus仿真

1.设计要求 运用模拟电路、数字电路知识&#xff0c;设计、制作一个8路智力竞赛抢答器&#xff0c;要求有优先锁存、数显、声响及复位电路。 主要元器件&#xff1a;CD4511&#xff0c;IN4148&#xff0c;共阴数码管&#xff0c;NPN三极管9013&#xff0c;NE555&#xff0c;喇叭…