C语言学习系列-->【函数的递归】
文章目录
- 前言
- 观图有感
- 一、概述
- 二、递归的限制条件
- 三、递归的代码实现
- 例1:求n!
- 例2:顺序打印⼀个整数的每⼀位
- 四、递归与迭代
前言
小编怀着激动的心情编写本篇小博客,因为我要介绍的是递归——一种优雅的问题解决方法。递归将人分成三个截然不同的阵营:恨它的、爱它的以及恨了几年后又爱上它的。
希望各位读者在阅读小编的文章后,可以深刻理解递归思想。
观图有感
为了让读者形象地认识到递归,先看一组漫画。
1、假设你在玩密室逃脱时,发现一个宝箱
2、NPC告诉你,钥匙很可能在下面这个盒子里。
3、这个盒子里有盒子,而盒子里的盒子又有盒子。钥匙就在某个盒子中。为了找到钥匙,苦逼的你尝试了不同的方法:
第一种方法:
(1)创建一个要查找的盒子堆。
(2) 从盒子堆取出一个盒子,在里面找。
(3) 如果找到的是盒子,就将其加入盒子堆中,以便以后再查找。
(4) 如果找到钥匙,则大功告成!
(5) 回到第二步。
第二种方法:
(1) 检查盒子中的每样东西。
(2) 如果是盒子,就回到第一步。
(3) 如果是钥匙,就大功告成!
在代码中,我们会发现,第一种方法就是while循环,第二种方法时函数调用自己。
两个方法都不差,但是欢Leigh Caldwell在Stack Overflow上说的一句话:“如果使用循环,程序的性能可能更高;如果使用递归,程序可能更容易理解。如何选择要看什么对你来说更重要”。
4、最终,你终于拿到钥匙,逃出密室。
一、概述
递归其实是⼀种解决问题的⽅法,在C语⾔中,递归就是函数⾃⼰调⽤⾃⼰。
举一个史上最简单的递归例子:
#include <stdio.h>
int main()
{printf("hehe\n");main();//main函数中⼜调⽤了main函数return 0;
}
上述就是⼀个简单的递归程序,只不过上⾯的递归只是为了演⽰递归的基本形式,不是为了解决问题,代码最终也会陷⼊死递归,导致栈溢出。
递归思想就是将大事化小的过程。
二、递归的限制条件
由于递归函数调用自己,因此编写这样的函数时很容易出错,进而导致
无限循环。
递归在书写的时候,有2个必要条件:
• 递归存在限制条件,当满⾜这个限制条件的时候,递归便不再继续。
• 每次递归调⽤之后越来越接近这个限制条件。
三、递归的代码实现
例1:求n!
公式:n! = n ∗ (n − 1)!
C code
# define _CRT_SECURE_NO_WARNINGS#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 ans = fact(n);printf("%d", ans);return 0;
}
红色箭头表示递推,只是将大事化小,并没有计算出结果;绿色箭头表示回归,计算结果返回上一级。
例2:顺序打印⼀个整数的每⼀位
输⼊⼀个整数n,打印这个按照顺序打印整数的每⼀位。
C code
# define _CRT_SECURE_NO_WARNINGS#include<stdio.h>void Print(int n) {if (n > 9) {Print(n / 10);}printf("%d ", n % 10);
}int main() {int n;scanf("%d", &n);Print(n);return 0;
}
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)
四、递归与迭代
在C语⾔中每⼀次函数调⽤,都要需要为本次函数调⽤在栈区申请⼀块内存空间来保存函数调⽤期间的各种局部变量的值,这块空间被称为运⾏时堆栈,或者函数栈帧。
函数不返回,函数对应的栈帧空间就⼀直占⽤,所以如果函数调⽤中存在递归调⽤的话,每⼀次递归函数调⽤都会开辟属于⾃⼰的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间。
所以如果采⽤函数递归的⽅式完成代码,递归层次太深,就会浪费太多的栈帧空间,也可能引起栈溢出(stack over flow)的问题。
事实上,我们看到的许多问题是以递归的形式进⾏解释的,这只是因为它⽐⾮递归的形式更加清晰,但是这些问题的迭代实现往往⽐递归实现效率更⾼。
当⼀个问题⾮常复杂,难以使⽤迭代的⽅式实现时,此时递归实现的简洁性便可以补偿它所带来的运⾏时开销。
有时候,递归虽好,但是也会引⼊⼀些问题,所以我们⼀定不要迷恋递归,适可⽽⽌就好。
C语言学习系列-->【函数的递归】相关推荐
- C语言学习记录——팔 函数和递归(1)
库函数 IO函数 字符串操作函数 (比如strlen) 字符操作函数(比如把大写转小写) 内存操作函数(memset) 时间/日期函数(time) 数学函数(sqrt开平方) 其他库函数 怎样使用文档 ...
- R语言学习系列之本地数据获取
R语言学习系列之本地数据获取 任何数据分析工作之前,都得把数据先读取进来你才能进行后续的分析工作.所以本文简要介绍在R中如何对本地文件进行获取,希望可以给刚刚接触R语言的同学一点启发. 一.控制台的输 ...
- Ruby语言学习系列--基本的ruby语法
Ruby语言学习系列--基本的ruby语法 1. 基本的ruby语法 1.1 变量.常量和类型 1) 定义变量 变量类型 描述 示例 局部变量(或伪变量) 以小写字母或下划 ...
- R语言学习系列之向量化计算
##R语言学习系列之向量化计算 本文主要讲解R语言向量化计算的原理及方法,希望对初学者能够提供帮助. ##一.向量化 什么是向量化计算呢?其实你可以简单的理解成这样:当我们在使用函数或者定义函数的时候 ...
- 黑马程序员——c语言学习心得——函数传递二维数组
黑马程序员--c语言学习心得--函数传递二维数组 -------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 一.定义指针的时候一定要初始化. 变量 ...
- 函数的返回值可以不用赋值_C语言学习|函数的应用《一》
C语言为程序的结构提供了函数和模块 一.函数的定义与使用 <编程之道>中写道:"一个程序应该是灵活自由的.它的子过程就像串在一根线子上的珍珠."子过程在C语言中被称为& ...
- C语言学习笔记--函数
1. C 语言中的函数 (1)函数的由来: 程序 = 数据 + 算法→C 程序 = 数据 + 函数 (2)模块化程序设计 (3)C 语言中的模块 2. 面向过程的程序设计 (1)面向过程是一种以过程为 ...
- C语言学习笔记——函数
1.函数的介绍 为完成某一功能的程序指令(语句)的集合,称为函数 在C语言中,函数分为: 自定义函数.系统函数 2.函数的定义 2.1函数的基本语法 返回类型 函数名(形参列表){执行语句...; / ...
- C语言学习笔记--函数与指针
1. 函数类型 (1)C 语言中的函数有自己特定的类型,这个类型由返回值.参数类型和参数个数共同决定.如 int add(int i,int j)的类型为 int(int,int). (2)C 语言中 ...
- c语言str系列函数
qsort() str系列函数 isalpha() 1,qsort() 功能: 快速排序,其时间复杂度为n*log(n) 头文件: <stdlib.h> 声明: void qsort(vo ...
最新文章
- SAP PR 转 PO
- OpenCV展开二维相位图
- MySQL查询中LIMIT的大offset导致性能低下浅析
- 20190423面试记录
- [转]Nginx的负载均衡方式
- CentOS 6服务器简单安全配置
- DBFace升级,模型仅1.3M的轻量级高精度人脸检测模型
- MSDTC on server 'xxx' is unavailable
- flv 开源 修复_解决开源项目错误和修复的5个步骤
- WebService学习总结(3)——使用java JDK开发WebService
- 全国计算机二级vb试题库,全国计算机等级考试题库之二级VB试题
- Nik插件滤镜套装Nik Collection 3 Mac
- dcx游走 - 组合计数
- 微信推送封面尺寸_微信公众号推送文图片什么尺寸最佳?
- ddl是什么意思网络语_跟随你大学的流行词语 DDL 你竟还不知道?
- Google是如何教会机器玩Atari游戏的
- 从零搭建Spring Boot脚手架(2):增加通用的功能
- [数据分析] 逻辑树分析方法
- 字节流、字节流、转换流、打印流
- act考试是什么意思?