C语言函数—递归理解和练习


练习:

编写函数不允许创建临时变量,求字符串的长度。

我们看到这道题,第一个想到的是不是strlen

int main()
{char[] = "bit";//['b']['i']['t']['\0']//里面一共4个字符(包括结尾的、0)但是我们的strlen函数并不会计算\0的长度,所以结果应该为10printf("%d\n",strlen(arr));return 0;
}

那我们写求字符串长度的函数,那不就是模拟实现strlen函数吗

我们把函数命名为my_strlen

我们再来思考一下,strlen传参穿的是什么呢?

是字符串首元素的地址

返回参数应该为字符串的长度,也就是整型变量

//多以我们的函数输入参数应该这么写
int my_strlen(char* str)
{}

里面怎么实现呢?

['b']['i']['t']['\0']//数组内容
//我们传递的参数一定是['b'],的地址,那strlen怎么知道字符串长度呢
//没错,就是去寻找['\0']

首先来看,计数怎么实现呢?

int my_strlen(char* str)
{int count = 0;while(*str != '\0'){count++;str++;//指针的偏移}return count;
}

我们看一下运行结果

image-20240315203248388

成功打印出了字符串的长度

很简单的实现方式,但是题目上要求是什么,不允许创建临时变量

我们在程序运行的过程中,创建了count作为临时变量,很明显是不对的

那我们该怎么做呢?

我们应该思考递归的想法

int my_strlen(char* str)
{}

我们重新来,怎么才能使用递归的思想呢?

什么是递归?

程序调用自身的编程技巧称为递归( recursion)。

递归做为一种算法在程序设计语言中广泛应用。

一个过程或函数在其定义或说明中有直接或间接 调用自身的 一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解, 递归策略 只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。

递归的主要思考方式在于:把大事化小


好,我们又复习了一下

大家请思考一下,我们是不是很容易就把第一个字符取出来(只判断第一个字符是不是\0)

my_strlen(“bit”);

1+my_strlen(“it”);

1+1+my_strlen(“t”);

1+1+1my_strlen(“”);

1+1+1+0

把大事化小

我们来看代码

int my_strlen(char* str)
{if (*str != '\0')//判断第一个字符是不是结束{return 1 + my_strlen(str+1);//如果第一个字符不是\0的话就即为1+剩下字符的长度}elsereturn 0}

我们看看结果

image-20240315205304167

哈哈,是不是真的很神奇

还有一个问题

return 1 + my_strlen(str+1);

写为

return 1 + my_strlen(str++);

行不行?

image-20240315205332558

为什么不行,因为str++是后置++

后置++是干什么的,先使用再++,也就是说传进去还是原来的值,留下来的是加1后的值,是不是就和我们想要的不一样了?

改为前置++就可以了

image-20240315205514231


第二个练习:

求n的阶乘。(不考虑溢出)

我们还是先写主函数

int main()
{int n;scanf("%d", &n);printf("%d\n", factorial(n));return 0;
}

那递归函数该怎么写呢?

//我们可以这么想
//每一次相乘都乘自己减去一,直到为0的时候,返回1

那函数是不是能这么写

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

很简单,我们来看一下结果

image-20240315211500608


练习三:斐波那契数列

什么是斐波那契数列?

image-20240315211941774

第一个数字为1,后面的数字都是前两个数字的和

那用递归的思想该怎么解决呢?

每一次迭代,都是自己加上前一个数字
return 自己上一个数字 + 上一个数字的上一个数字当然,递归终结条件就是到2以下的时候,当自己小于等于2,直接返回1就行

是不是还是很不好理解,那我再举一个更详细的例子

我现在要求第五个斐波那契数列的数字1.我们需要求第四个数字加第三个数字2.我们需要求出   第二个数字+第三个数字(第四个数字)   +   第一个数字+第二个数字(第三个数字)//注意了,这里出现了循环终结条件,斐波那契数列的第一个和第二个数字都为1,那么可以直接带入
3.我们需要求出   1 +  第一个数字+第二个数字(第三个数字)    +    1 +1 4.那么递归都来到了递归终结条件,开始整个程序出栈计算结果,结果就是 1+1+1+1+1 = 5

所以我们可以推导出来这个函数

int Fib(int n)
{if(n <= 2)return 1;elsereturn Fib(n-1)+Fib(n-2);
}

看一下计算结果

image-20240315214217106

这里还有一个问题,如果我要求第五十个数字呢?

运行时你就会发现,程序一直在计算,是程序偷懒了算不出来结果吗

我们如果看一下计算过程就会发现,整个程序的复杂度是2的n次方,也就是说我如果要计算第五十个数字,需要计算1125899906842624次

效率太低 —— 重复大量的计算

那该如何避免重复的计算呢,很简单其实,我们从前往后算就行,让前两个数相加等于第三个数,一直到第n个数为止

#include <stdio.h>
int Fib(int n)
{int i = 0;int a = 1;int b = 1;int c = 1;//当不进入数列时直接返回C,所以把C初始化为1while(n > 2){c = a + b;a = b;b = c;n--;}return c;
}int main()
{int n;scanf("%d", &n);printf("%d\n", Fib(n));return 0;
} 

很容易理解,我们可以测试一下

image-20240315215225519

这次的时间复杂度O(n)就很低

直接计算第五十个数也是会在1秒内算出答案,但是因为整型表示范围有限溢出了,这里就不放图了


我们的代码可以用递归写,也可以用非递归来写

有时候当我们使用递归时,可能会导致栈溢出,大量的重复计算导致的效率低下

我们总是要想出一个方法要用非递归的方法来写

这个时候再难也要去找i到这样一种非递归的方法


最后一个递归问题,也是最经典的一个迭代问题

汉诺塔

经典的递归的问题

image-20240315215938345

image-20240315220000136

我总结一下

  • 一共有三根柱子,第一根柱子有从大到小的圆盘
  • 我们需要把圆盘移到第三根柱子上
  • 每次只能挪动一个
  • 小圆盘只能在大圆盘的上面

现在有n个圆盘那我们该如何通过程序算出来最少需要多少次移动才能成功呢?

大家可以思考一下

会尽快快更新笔记讲解这个问题的?


感谢大家的阅读!!!

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

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

相关文章

mysql 常用命令

1、显示锁的时间 show status like innodb_row_lock%;2、锁一行的方法 //开启 begin; //锁一行 select * from tbl_user where name 1aa1 for update;//解锁 commit;3、设置不自动提交 set autocommit 0; //自动提交 set autocommit 1;4、查看是否支持profile show vari…

洛谷P1182数列分段

题目描述 对于给定的一个长度为 N 的正整数数列 &#xff0c;现要将其分成 M&#xff08;M≤N&#xff09;段&#xff0c;并要求每段连续&#xff0c;且每段和的最大值最小。 关于最大值最小&#xff1a; 例如一数列 4 2 4 5 14 2 4 5 1 要分成 33 段。 将其如下分段&#…

信雅纳网络测试的二次开发集成:XOA(Xena Open-Source Automation)开源自动化测试

目录 XOA是什么 XOA CLI XOA Python API ​XOA Python Test Suite/测试套件 XOA Converter Source Code XOA是什么 XOA&#xff08;Xena Open-Source Automation&#xff09;是一个开源的测试自动化框架&#xff0c;追求“高效、易用、灵活”的跨操作系统的开发框架。能…

细说C++反向迭代器:原理与用法

文章目录 一、引言二、反向迭代器的原理与实现细节三、模拟实现C反向迭代器反向迭代器模板类的设计反向迭代器的使用示例与测试 一、引言 迭代器与反向迭代器的概念引入 迭代器&#xff08;Iterator&#xff09;是C标准模板库&#xff08;STL&#xff09;中的一个核心概念&am…

3.15作业

1、思维导图 2、模拟面试题 1&#xff09;什么是IP地址&#xff1f; 答&#xff1a;ip地址是主机在网络中的唯一标识&#xff0c;分为IPv4和IPv6&#xff0c;IP网络号主机号 2&#xff09;IP地址和MAC地址的区别 答&#xff1a;IP地址是由数字和点分十进制表示的主机在网络中…

VS2022 配置QT5.9.9

QT安装 下载地址:https://download.qt.io/archive/qt/ 下载安装后进行配置 无法运行 rc.exe 下载VS2022 官网下载 配置 1.扩展-管理扩展-下载Qt Visual Studio Tools 安装 2.安装完成后,打开vs2022,点击扩展,会发现多出了QT VS Tools,点击它,选择Qt Versions并进行配置…

Java开发从入门到精通(七):Java的面向对象编程OOP:语法、原理、this、构造器

Java大数据开发和安全开发 &#xff08;一&#xff09;Java的面向对象编程1.1 什么是面向对象1.2 面向对象和面向过程的区别1.3 面向对象开发设计特征1.4 面向对象语法1.4.1 先创建对象模板1.4.2 实例化对象1.4.3 对象又该怎么理解?1.4.4 对象在计算机中的执行原理 1.5 类和对…

python:消息推送 - 飞书机器人推送 - 富文本格式

简介&#xff1a;机器人 ( bot ) 是一种自动化的程序&#xff0c;可以用拟人化的身份自动推送消息&#xff0c;或在聊天里与你进行简单的交互。在自动化完成测试任务后&#xff0c;推送测试报告等是一种很常用的收尾工具。 历史攻略&#xff1a; python&#xff1a;消息推送 …

搭建知识管理系统并不复杂,这篇教程来帮你

许多人都有这样的体验&#xff1a;我们抓住的想法和知识总在不经意间溜走&#xff0c;我们想要的信息总是一时无法找到。因此&#xff0c;搭建一个能够系统化、分类和索引存储这些知识的“知识管理系统”是必要的。听上去很专业&#xff0c;其实并不复杂&#xff0c;让我们一步…

单目测距+姿态识别+yolov8界面+车辆行人跟踪计数

yolov5单目测距速度测量目标跟踪&#xff08;算法介绍和代码&#xff09; 1.单目测距实现方法 在目标检测的基础上&#xff0c;我们可以通过计算物体在图像中的像素大小来估计其距离。具体方法是&#xff0c;首先确定某个物体的实际尺寸&#xff0c;然后根据该物体在图像中的像…

可视化展示与交互编辑:探索3D Web轻量化平台HOOPS WEB Platform在BIM中的新可能性

随着数字技术的飞速发展&#xff0c;建筑行业也在不断迈向数字化转型的道路。在这个过程中&#xff0c;BIM&#xff08;Building Information Modeling&#xff0c;建筑信息模型&#xff09;技术已经成为建筑设计、施工和管理领域中的一项重要工具。 而在BIM的应用中&#xff…