LeetCode递归 -2(Recursion) 培训专题 讲解文章翻译 (附连接) (2019-04-09 15:50)

递归 - 空间复杂度 

在本文中, 咱们将讨论如何分析递归算法的空间复杂度.
在计算递归算法的空间复杂度时,最须要考虑的两个部分就是: 递归相关空间 (recursion related space)和非递归相关空间(non-recursion related space).

递归相关空间


递归相关空间指的是递归直接产生的内存开销,也就是在递归调用过程当中开辟的堆栈内存空间。为了完成一个典型的函数调用,系统中在开辟内存空间时,会存放一下3个重要的数据信息:
  1. 调用函数的返回地址. 一旦程序调用结束,须要这个地址返回, 即程序调用结束进行下一步的地址; 
  2. 该调用函数所须要的参数; 
  3. 调用函数的内部变量.
尽管堆栈是在递归调用时产生的最小消耗. 旦只要调用过程结束,这些空间也会被释放掉。 
对于递归算法,函数的调用将会持续产生调用链,直至调用到基本型 (base case) (亦称做. bottom case).这意味着每一个函数的调用也是逐步累积的.
对于递归算法, 若是没有其余的内存消耗, 这个算法的空间上限就是该递归调用直接产生的内存开销。
仍是拿练习  printReverse说事,咱们每次调用只是打印了一个字符,因此在递归调用以外咱们没有用掉其余的内存开销, .对于每一次的递归调用, 假设须要一个固定常量的空间. 那么根据前面的分析,他会调用 n 次函数链,  n 就是输入的字串长度. 因此该算法的空间复杂度即为 {\mathcal{O}(n)}O(n).
为了更好地说明, 对于递归调用序列 f(x1) -> f(x2) -> f(x3) 的执行步骤序列以及堆栈的布局以下图所示:
 f(x1) 将会被分配必定额外的空间以便调用f(x2). 对于 f(x2)调用f(x3).时候的内存操做也是一样类型的状况,直到 f(x3),的调用到达了基本型, 当到达 f(x3).时,不在分配额外空间。
这种调用机制致使有时分配给堆栈的空间有时超出内存限制,会致使一种程序崩溃的状况,叫作栈溢出( stack overflow),因此当设计采用这种递归调用机制的程序时,首要考虑的就是输入量是否会致使溢出状况的发生。
 

非递归相关空间 


显而易见, 所谓非递归相关空间即与递归调用链过程当中不直接相关的内存开销, 好比为全局变量所分配的空间(通常状况下都存放在堆heap中).
不管是否是递归程序,在执行下一个子程序以前总须要一个全局变量来存放输入的数据。  一样对于调用函数的返回值也须要开辟空间来存放.后者的一种状况就是咱们前面讨论过的 记忆化 处理方式. 例如在处理斐波那契额数列的记忆化递归算法中, 咱们使用一个map来存储每次递归调用返回的结果值. 所以, 在计算该算法的空间复杂度的时候, 咱们同时也须要考虑记忆化操做所带来的空间成本.  
相关文章
相关标签/搜索