【基础篇】8 # 递归:如何避免出现堆栈溢出呢?

简介: 【基础篇】8 # 递归:如何避免出现堆栈溢出呢?

说明

【数据结构与算法之美】专栏学习笔记



什么是递归?


递归是一种应用非常广泛的算法(或者编程技巧),比如 DFS 深度优先搜索、前中后序二叉树遍历等等都是用到了递归。


方法或函数调用自身的方式称为递归调用,调用称为递,返回称为归。


递归问题基本都可以用递推公式来表示,比如:

f(1) = 1;
f(n) = f(n-1) + 1; // n 是大于 1 的正整数



递归需要满足的三个条件

  1. 一个问题的解可以分解为几个子问题的解
  2. 分解之后的子问题求解思路一样
  3. 存在递归终止条件


如何编写递归代码?

写递归代码的关键就是找到如何将大问题分解为小问题的规律,并且基于此写出递推公式,然后再推敲终止条件,最后将递推公式和终止条件翻译成代码。


编写递归代码的关键是,只要遇到递归,我们就把它抽象成一个递推公式,不用想一层层的调用关系,不要试图用人脑去分解递归的每个步骤。



如何避免出现堆栈溢出呢?


为什么递归代码容易造成堆栈溢出呢?

函数调用会使用栈来保存临时变量。每调用一个函数,都会将临时变量封装为栈帧压入内存栈,等函数执行完成返回时,才出栈。系统栈或者虚拟机栈空间一般都不大。如果递归求解的数据规模很大,调用层次很深,一直压入栈,就会有堆栈溢出的风险。


如何预防堆栈溢出呢?

可以通过在代码中限制递归调用的最大深度的方式来解决。递归调用超过一定深度之后,不继续往下再递归,直接返回报错。


如何避免重复计算呢?

可以通过一个数据结构(比如散列表)来保存已经求解过的 f(k)。当递归调用到 f(k) 时,先看下是否已经求解过;如果是,则直接从散列表中取值返回,不需要重复计算。



怎么将递归代码改写为非递归代码?


递归代码优点:


  • 表达力很强
  • 写起来非常简洁

递归代码缺点:


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



笼统的讲,所有的递归代码都可以改写为迭代循环的非递归写法。抽象出递推公式、初始值和边界条件,然后用迭代循环实现。



调试递归


  1. 打印日志发现,递归值。
  2. 结合条件断点进行调试。






目录
相关文章
|
存储
最粗暴的方法实现一个栈
最粗暴的方法实现一个栈
60 1
|
4月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
64 1
|
7月前
|
存储 算法 Java
惊!Java程序员必看:JVM调优揭秘,堆溢出、栈溢出如何巧妙化解?
【8月更文挑战第29天】在Java领域,JVM是代码运行的基础,但需适当调优以发挥最佳性能。本文探讨了JVM中常见的堆溢出和栈溢出问题及其解决方法。堆溢出发生在堆空间不足时,可通过增加堆空间、优化代码及释放对象解决;栈溢出则因递归调用过深或线程过多引起,调整栈大小、优化算法和使用线程池可有效应对。通过合理配置和调优JVM,可确保Java应用稳定高效运行。
187 4
|
8月前
|
测试技术 编译器
栈溢出处理
栈溢出处理
159 2
|
8月前
|
监控 算法 Java
JVM调优---堆溢出,栈溢出的出现场景以及解决方案
【7月更文挑战第3天】堆溢出(Heap Overflow)和栈溢出(Stack Overflow)是两种常见的内存溢出问题,通常发生在内存管理不当或设计不合理的情况下
135 3
|
9月前
|
存储 Java 编译器
技术经验解读:【堆栈溢出】堆栈溢出
技术经验解读:【堆栈溢出】堆栈溢出
|
10月前
|
存储 算法
堆的知识点总结
堆的知识点总结
99 1
|
10月前
|
存储 算法 安全
堆的应用例子
【5月更文挑战第6天】堆栈是一种LIFO(后进先出)数据结构,支持push、pop、isEmpty、isFull和peek等操作。内部使用切片存储接口类型的元素
91 0
堆的应用例子
|
10月前
|
存储 编译器 C语言
C陷阱:数组越界遍历,不报错却出现死循环?从内存解析角度看数组与局部变量之“爱恨纠葛”
在代码练习中,通常会避免数组越界访问,但如果运行了这样的代码,可能会导致未定义行为,例如死循环。当循环遍历数组时,如果下标超出数组长度,程序可能会持续停留在循环体内。这种情况的发生与数组和局部变量(如循环变量)在内存中的布局有关。在某些编译器和环境下,数组和局部变量可能在栈上相邻存储,数组越界访问可能会修改到循环变量的值,导致循环条件始终满足,从而形成死循环。理解这种情况有助于我们更好地理解和预防这类编程错误。
203 0
|
10月前
|
存储 Java
什么情况下会产生StackOverflowError(栈溢出)和OutOfMemoryError(堆溢出)怎么排查
什么情况下会产生StackOverflowError(栈溢出)和OutOfMemoryError(堆溢出)怎么排查