10|递归

作者: 攻城虱小马褂 | 来源:发表于2019-03-10 09:35 被阅读0次

如何理解递归

递归是一个广泛的编程技巧,如DFS深度优先搜索、前中后序二叉树遍历。

递归满足的三个条件

1.一个问题的解可以分解为几个子问题的解

2.这个问题与分解之后的子问题,除了数据规模不同,求解思路完全一样。

3.存在递归终止条件。

如何编写递归代码

关键:

1.如何将大问题分解为小问题的规律,基于此写出递推公示,在推敲终止条件,最后将地推公式和终止条件翻译成代码

2.递归代码不好理解,人脑没办法把这个“递”和“归”的过程想清楚,人脑更适合平铺直叙的四维方式,所以不要试图搞清楚计算机每一步是怎样执行的,会被绕进去。

3.一个问题A可以分解为若干子问题B、C、D,假设B、C、D已经解决,在此基础上思考如何解决问题A,只需思考问题A与问题B、C、D两层的关系即可,不需要一层一层往下思考子问题与子子问题的关系,屏蔽掉递归细节

警惕堆栈溢出

递归代码会造成堆栈溢出,堆栈溢出会造成系统崩溃。

函数调用使用栈来保存临时变量,每调用一个函数,都会讲临时变量封装成栈帧压入内存栈,等函数执行完成再出栈,一般情况系统栈和虚拟机栈空间都不大,当递归代码求解数据规模很大时,调用层次很深,一直压入栈就会有堆栈溢出的风险。

如何避免

限制递归最大深度(适合于最大深度比较小的情况)

警惕重复计算

利用散列表来保存已经求解过的值

问题:

时间效率上,递归游很多函数调用,函数调用交大时,就回积聚成可观的时间成本

空间复杂度上,递归调用一次就回在内存栈保存一次现场数据,所以分析空间复杂度的时候需要额外考虑这部分的开销

递归改为非递归

(1)递归表达力强,简洁

(2)空间复杂度高,有堆栈溢出的风险,存在重复计算,过多函数调用耗时较多

所以可以根据实际情况选择是否用递归来实现,可以将递归改为非递归实现


写在最后

问题:

1.对于无线递归的问题

(1)限制递归深度

(2)检测递归环

2. 递归代码如何调试

打印日志发现递归值,结合断点进行调试。

相关文章

网友评论

      本文标题:10|递归

      本文链接:https://www.haomeiwen.com/subject/plzypqtx.html