C语言(第三十三天)

3.1.2 画图推演

 3.2 举例2:顺序打印一个整数的每一位
输入一个整数m,打印这个按照顺序打印整数的每一位。
比如:
输入:1234 输出:1 2 3 4
输入:520 输出:5 2 0
3.2.1 分析和代码实现
这个题目,放在我们面前,首先想到的是,怎么得到这个数的每一位呢?
如果n是一位数,n的每一位就是n自己

n是超过1位数的话,就得拆分每一位
1234%10就能得到4,然后1234/10得到123,这就相当于去掉了4
然后继续对123%10,就得到了3,再除10去掉3,以此类推
不断的%10 和\10 操作,直到1234的每一位都得到;
但是这里有个问题就是得到的数字顺序是倒着的
但是我们有了灵感,我们发现其实一个数字的最低位是最容易得到的,通过%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
完成上述2步,那就完成了1234每一位的打印
那么Print(123)又可以拆分为Print(123/10) + printf(123%10)

以此类推下去,就有

    Print(1234)
==>Print(123) + printf(4)
==>Print(12) + printf(3)
==>Print(1) + printf(2)
==>printf(1)

直到被打印的数字变成一位数的时候,就不需要再拆分,递归结束。
那么代码完成也就比较清楚:

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.2 画图推演
以1234每一位的打印来推演一下

 4. 递归与迭代

递归是一种很好的编程技巧,但是很多技巧一样,也是可能被误用的,就像举例1一样,看到推导的公式,很容易就被写成递归的形式:

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

 Fact函数是可以产生正确的结果,但是在递归函数调用的过程中涉及一些运行时的开销。
在C语言中每一次函数调用,都要需要为本次函数调用在栈区申请一块内存空间来保存函数调用期间的各种局部变量的值,这块空间被称为运行时堆栈,或者函数栈帧。
函数不返回,函数对应的栈帧空间就一直占用,所以如果函数调用中存在递归调用的话,每一次递归函数调用都会开辟属于自己的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间。
所以如果采用函数递归的方式完成代码,递归层次太深,就会浪费太多的栈帧空间,也可能引起栈溢出(stack over flow)的问题。
关于函数栈帧的详细内容,鹏哥录制了注: 视频专门讲解的,下课导入课程,自行学习。
所以如果不想使用递归就得想其他的办法,通常就是迭代的方式(通常就是循环的方式)。
比如:计算n的阶乘,也是可以产生1~n的数字累计乘在一起的。

int Fact(int n)
{int i = 0;int ret = 1;for(i=1; i<=n; i++){ret *= i;}return ret;
}

上述代码是能够完成任务,并且效率是比递归的方式更好的。

事实上,我们看到的许多问题是以递归的形式进行解释的,这只是因为它比非递归的形式更加清晰,但是这些问题的迭代实现往往比递归实现效率更高。
当一个问题非常复杂,难以使用迭代的方式实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开销。

举例3:求第n个斐波那契数
我们也能举出更加极端的例子,就像计算第n个斐波那契数,是不适合使用递归求解的,但是斐波那契数的问题通过是使用递归的形式描述的,如下:

看到这公式,很容易诱导我们将代码写成递归的形式,如下所示:

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

 测试代码:

#include <stdio.h>
int main()
{int n = 0;scanf("%d", &n);int ret = Fib(n);printf("%d\n", ret);return 0;
}

当我们n输入为50的时候,需要很长时间才能算出结果,这个计算所花费的时间,是我们很难接受的,这也说明递归的写法是非常低效的,那是为什么呢?

 其实递归程序会不断的展开,在展开的过程中,我们很容易就能发现,在递归的过程中会有重复计算,而且递归层次越深,冗余计算就会越多。我们可以作业测试:

#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个斐波那契数的时候,使用递归方式,第3个斐波那契数就被重复计算了39088169次,这些计算是非常冗余的。所以斐波那契数的计算,使用递归是非常不明智的,我们就得想迭代的方式解决。
我们知道斐波那契数的前2个数都1,然后前2个数相加就是第3个数,那么我们从前往后,从小到大计算就行了。
这样就有下面的代码:

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;
}

迭代的方式去实现这个代码,效率就要高出很多了。

有时候,递归虽好,但是也会引入一些问题,所以我们一定不要迷恋递归,适可而止就好。

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

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

相关文章

方案:AI边缘计算智慧工地解决方案

一、方案背景 在工程项目管理中&#xff0c;工程施工现场涉及面广&#xff0c;多种元素交叉&#xff0c;状况较为复杂&#xff0c;如人员出入、机械运行、物料运输等。特别是传统的现场管理模式依赖于管理人员的现场巡查。当发现安全风险时&#xff0c;需要提前报告&#xff0…

javaCV实现java图片ocr提取文字效果

引入依赖&#xff1a; <dependency><groupId>org.bytedeco</groupId><artifactId>javacv-platform</artifactId><version>1.5.5</version></dependency> 引入中文语言训练数据集&#xff1a;chi_sim GitHub - tesseract-ocr…

windows下如何搭建属于自己的git服务器

前一阵子公司需要&#xff0c;领导让我给我们技术部搭建一个git服务器。以前看过教程&#xff0c;但自己没动手做过&#xff0c;开始按照网上的教程来&#xff0c;但搭建过程中发现还是不够详细&#xff0c;今天给大家一个比较详细的&#xff0c;希望对大家有帮助。 高能预警&a…

容器化微服务:用Kubernetes实现弹性部署

随着云计算的迅猛发展&#xff0c;容器化和微服务架构成为了构建现代应用的重要方式。而在这个过程中&#xff0c;Kubernetes&#xff08;常简称为K8s&#xff09;作为一个开源的容器编排平台&#xff0c;正在引领着容器化微服务的部署和管理革命。本文将深入探讨容器化微服务的…

关于 Camera 预览和录像画质不一样的问题分析

1、问题背景 基于之前安卓平台的一个项目&#xff0c;客户有反馈过一个 Camera app 预览的效果&#xff0c;和录像效果不一致的问题。 这里的预览是指打开 Camera app 后直接出图的效果&#xff1b;录像的效果则是指打开 Camera app 开启录像功能&#xff0c;录制一段视频&…

数据库——Redis 没有使用多线程?为什么不使用多线程?

文章目录 Redis6.0 之后为何引入了多线程&#xff1f; 虽然说 Redis 是单线程模型&#xff0c;但是&#xff0c; 实际上&#xff0c;Redis 在 4.0 之后的版本中就已经加入了对多线程的支持。 不过&#xff0c;Redis 4.0 增加的多线程主要是针对一些大键值对的删除操作的命令&a…

嵌入式linux之QT交叉编译环境搭建(最简单实测通用版)

这里总结下用于嵌入式linux下的QT交叉编译环境搭建&#xff0c;留作备忘&#xff0c;分享给有需要的小伙伴。不管你的是什么嵌入式linux环境&#xff0c;实测过的通用方法总结。 环境准备 需要准备的环境要求如下&#xff1a; 1.虚拟机(vmvare15.5) 2.ubuntu18.04-x64的linu…

Linux 基金会宣布正式进驻中国

在 LinuxCon 2017 &#xff08;北京&#xff09;即将召开前夕&#xff0c;我们Linux 中国会同 51CTO、开源中国对 Linux 基金会执行董事 Jim Zemlin 进行了一场远跨大洋的视频专访。 在这次专访中&#xff0c;Jim 先生回答了几个开源界和互联网领域关注的问题&#xff0c;并披…

Vue3.0极速入门 - 登录demo

Talk is cheap, Show the code 在完成npm和vue的环境安装&#xff0c;并了解了基本的目录和文件结构以后&#xff0c;直接写一个带登录和首页的demo做示例&#xff0c;快速了解一个vue工程的创建和基本的页面跳转 第一步创建工程 1、选择手动模式创建工程 npm create app-…

云服务器(Centos7系统)配置JAVA+mysql+tomcat 环境

文章主要内容来源云服务器&#xff08;Centos7系统&#xff09;部署javaweb项目&#xff08;二&#xff09;配置JAVAmysqltomcat 环境_man_zuo的博客-CSDN博客 模仿途中遇到的问题 连接无效 有时连接无法下载&#xff0c;可能是过期了&#xff0c;将其更换为官网给的下载连接即…

五、Kafka消费者

目录 5.1 Kafka的消费方式5.2 Kafka 消费者工作流程1、总体流程2、消费者组原理3、消费者组初始化流程4、消费者组详细消费流程 5.3 消费者API1 独立消费者案例&#xff08;订阅主题&#xff09;2 独立消费者案例&#xff08;订阅分区&#xff09;3 消费者组案例 5.4 生产经验—…

4.22 TCP 四次挥手,可以变成三次吗?

目录 为什么 TCP 挥手需要四次呢&#xff1f; 粗暴关闭 vs 优雅关闭 close函数 shotdown函数 什么情况会出现三次挥手&#xff1f; 什么是 TCP 延迟确认机制&#xff1f; TCP 序列号和确认号是如何变化的&#xff1f; 在一些情况下&#xff0c; TCP 四次挥手是可以变成 T…

冲破时代鸿沟,Linus和Eversheet,杰出程序员的创新成果

在80年代末&#xff0c;电脑技术的普及程度与今日相较&#xff0c;犹如鸿沟天堑。那时&#xff0c;计算机对大多数人来说还是稀罕物&#xff0c;尤其在像中国这样的发展中国家。 与如今充满信息的网络环境相比&#xff0c;那个时代没有Web&#xff0c;没有Google等搜索引擎&am…

Docker安装并配置Pushgateway

Linux下安装Docker请参考&#xff1a;Linux安装Docker 简介 Pushgateway是Prometheus的一个组件&#xff0c;prometheus server默认是通过Exporter主动获取数据&#xff08;默认采取pull拉取数据&#xff09;&#xff0c;Pushgateway则是通过exporter主动方式推送数据到Pushg…

SQLmap使用

文章目录 利用sqlmap 注入得到cms网站后台管理员账密获取数据库名称获取cms数据库的表名获取users表中的字段&#xff08;内容&#xff09;获取username字段和password字段的内容 salmap破解psot请求数据包salmap获取getshell 利用sqlmap 注入得到cms网站后台管理员账密 获取数…

机器人制作开源方案 | 桌面级机械臂--本体说明+驱动及控制

一、本体说明 1. 机械臂整体描述 该桌面级机械臂为模块化设计&#xff0c;包含主机模块1个、转台模块1个、二级摆动模块1个、可编程示教盒1个、2种末端执行器、高清摄像头&#xff0c;以及适配器、组装工具、备用零件等。可将模块快速组合为一个带被动关节的串联3自由度机械臂…

Maven详解

文章目录 一、引言1.1 为什么需要 Maven&#xff1f;1.2 Maven 解决了哪些问题&#xff1f;1.2.1 添加第三方jar包1.2.2 jar包之间的依赖关系1.2.3 处理jar包之间的冲突1.2.4 获取第三方jar包1.2.5 将项目拆分成多个工程模块1.2.6 实现项目的分布式部署 二、介绍三、Maven 的特…

python数组基本使用

使用Numpy进行数组运算 相比 List&#xff0c;NumPy 数组的优势 NumPy 全称为 Numerical Python&#xff0c;是 Python 的一个以矩阵为主的用于科学计算的基础软件包。NumPy 和 Pandas、Matpotlib 经常结合一起使用&#xff0c;所以被人们合称为数据分析三剑客。Numpy 中有功能…

winpe还原windows系统备份

准备工作 用大白菜制作一个启动u盘&#xff0c;里面可以镜系统备份文件 插入电脑&#xff0c;启动&#xff0c;按f11&#xff08;这个快捷键因电脑而异&#xff09;&#xff0c;选择启动u盘&#xff0c;进入winpe 硬盘格式化 选择分区助手软件 选择硬盘&#xff0c;右键选择【…

【Java 中级】一文精通 Spring MVC - 数据验证(七)

&#x1f449;博主介绍&#xff1a; 博主从事应用安全和大数据领域&#xff0c;有8年研发经验&#xff0c;5年面试官经验&#xff0c;Java技术专家&#xff0c;WEB架构师&#xff0c;阿里云专家博主&#xff0c;华为云云享专家&#xff0c;51CTO 专家博主 ⛪️ 个人社区&#x…