谈一谈递归算法
今天分享的是递归算法,为了后面的二叉树做铺垫。递归是一种非常重要的算法,应用递归算法,可以方便的解决很多问题。但是递归分析起来可能会觉得非常绕,一不小心就出不来了。递归说白了就是自己调用自己,关于递归,有几点需要特别注意的地方:
1、递归的终止条件是什么?递归一定需要终止条件,否则就变成了死循环。
2、递归的最后一次是什么情况?
3、一次递归完成了什么事情?
下面是求阶乘的递归图,可以看到,递归需要一层层的进去,遇到终止条件之后还需要一层层的出来。
下面通过例子来讲解关于递归的一些操作。
#include<stdio.h>
void test(int n)
{
if(n<0){
return;
}
printf("%d ",n);
test(n-1);
}
int main()
{
test(2);
}
在这个例子里面,相信大家很容易可以得出执行的结果是2,1,0。这个没有什么难度。
如果把printf("%d ",n);放在test(n-1)的后面呢?
void test(int n)
{
if(n<0){
return;
}
test(n-1);
printf("%d ",n);
}
估计有人开始犹豫了,应该打印出什么?打印出-1吗?当然不是。结果是0,1,2。
这里只是把打印语句和递归函数调了一下位置,结果就倒过来了。
为什么结果是这样子的呢?可以这样分析:
首先主函数调用test(2)的时候,我们如果不考虑递归,应该是执行
//伪代码,只表示含义
test(1);
printf 2;
这样就执行完了,只不过由于这个是递归,应该要把test(1)给展开,展开成test(0) 和printf 1;
这样还不够,还得把test(0)展开,展开成test(-1)和printf 0;
通过这样层层展开,就知道最先打印的是0,然后是1,最后是2。
通过以上分析可以知道,递归是有先序递归和后序递归之分,这两种递归的结果刚好是逆序的。
接下来继续增加难度:
#include<stdio.h>
void test(int n)
{
if(n<0){
return;
}
printf("%d ",n);
test(n-1);
printf("#%d ",n);
test(n-1);
printf("*%d ",n);
}
int main()
{
test(2);
}
如果能把这个打印结果理清楚,那么就说明对递归有一定理解了。
这里面有两次调用递归,在递归前后都加了打印语句,打印语句里面加上#和*符号用来区分是哪个地方打印的。
估计可以比较容易想到最先打印的肯定是2,1,0。但是打印完2 1 0 之后应该打印什么?好像应该往下执行printf("#%d ",n)语句,但此时的n究竟是多少?
如果这样思考很容易陷进去,然后就不知道怎么出来了。先把结果放在这里,看结果和你想的是不是一样的。
打印出来了一串数字。其实分析方法还是用刚刚的展开法就很好做,按照展开法,应该是:
printf 2;
test(1);
printf #2;
test(1);
printf *2;
这就是整个过程,接下来只要把里面的test(1)用同样的方法展开,就可以知道为什么是上面的打印结果了。
这就是涉及到两层递归的时候,用展开法还是非常好分析,同时也得出一些经验:遇到递归不要立马带进去算,因为现在就带进去容易把后面的忘记,而且你也不知道究竟有多少层才能结束。我们只要把递归当作一个标号一样,先记录一下,然后把后面的执行完,等后面所有的都执行完了之后,再把里面的递归一层层展开,这样就可以做到不重不漏,而且不会把自己陷进去。
以上就是关于递归的一些分析方法。
- 为服务器控件加入客户端事件处理的几种方法
- 温故而知新:Delegate,Action,Func,匿名方法,匿名委托,事件
- 如何在Silverlight4中使用摄像头
- Flask的集中控制
- 64位IIS(IIS6/IIS7)上跑Asp + Jet.Oledb的设置要点
- windows 2003 32位系统能支持的最大内存数
- .Net Core内存回收模式及性能测试对比
- silverlight中顺序/倒序异步加载多张图片
- MySQL数据库性能优化之三
- 谁说 Java 要过时?2017年Java 大事件一览及未来前瞻
- mongodb的用法
- silverlight中如何将string(字符串)写入Resource(资源)?
- Python练习环境搭建-引入预定义数据
- 振幅和成交量的关系
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 如何写出让同事无法维护的代码?
- 浅谈php://filter的妙用
- PHP中“=>
- CI(CodeIgniter)框架中URL特殊字符处理与SQL注入隐患分析
- PHP实现获取毫秒时间戳的方法【使用microtime()函数】
- 利用PHP如何统计Nginx日志的User Agent数据
- PHP树形结构tree类用法示例
- PHP PDOStatement::errorCode讲解
- Laravel框架搜索分页功能示例
- 解决Keras TensorFlow 混编中 trainable=False设置无效问题
- 浅谈keras中的后端backend及其相关函数(K.prod,K.cast)
- 使用 prometheus python 库编写自定义指标的方法(完整代码)
- PHP PDOStatement::fetchColumn讲解
- PHP PDOStatement::bindValue讲解
- PDO::lastInsertId讲解