递归

作者: _1633_ | 来源:发表于2021-01-26 23:18 被阅读0次

    每个递归函数都有两部分:基线条件(base case) 和 递归条件(recursive case)。递归条件指的是 函数调用自己,而基线条件则指的是函数不再调用自己,从而避免形成无线循环。

递归需要满足的三个条件

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

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

  3.存在递归终止条件。

如何编写递归代码?

  写递归代码最关键的是写出递推公式(找到如何将大问题分解为小问题的规律),找到终止条件,剩下将递推公式转化为代码就很简单了。

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


递归代码要警惕堆栈溢出

    在递归过程中,我们需要注意堆栈溢出的问题。在递归过程中,函数会被压入栈中,如果递归调用的深度过高,就会有用溢出栈的风险。

    我们可以通过限制代码中递归调用的最大深度的方式解决这个问题。递归调用超过一定深度之后,就不在继续调用下去。

递归代码要警惕重复计算

    就像斐波那契数列一样,如果不做一些缓存的处理,那么就会出现大量的重复计算,大大增加了时间复杂度。

将递归代码改成非递归代码

    f(x) =f(x-1)+1;

    f(int n) {

         let ret = 1;

         for (let i = 2; i <= n; ++i) {

            ret = ret + 1;

        }

        return ret;

    }

    是不是所有的递归代码都可以改为这种迭代循环的非递归写法呢?

    笼统地讲,是的。因为递归本身就是借助栈来实现的,只不过我们使用的栈是系统或者虚拟机本身提供的,我们没有感知罢了。如果我们自己在内存堆上实现栈,手动模拟入栈、出栈过程,这样任何递归代码都可以改写成看上去不是递归代码的样子。

    但是这种思路实际上是将递归改为了“手动”递归,本质并没有变,而且也并没有解决前面讲到的某些问题,徒增了实现的复杂度。

相关文章

  • 二叉树遍历

    先序遍历——[递归、非递归] 中序遍历——[递归、非递归] 后序遍历——[递归、非递归] 层次遍历——[递归、非递归]

  • 二叉树的遍历

    先序递归: 非递归: 中序递归: 非递归: 后序递归: 非递归 层次遍历

  • 二叉树的前序、中序、后序遍历(递归、非递归)

    二叉树 前序 递归: 非递归: 中序 递归: 非递归: 层序 递归: 非递归:

  • 树的遍历,golang实现

    先序,递归 中序,递归 后序,递归 先序,非递归 中序,非递归 后序,非递归 层序遍历

  • 3 递归(19)(方法层面的高级循环)

    递归 树的递归 其它递归

  • 递归,递归,递归

    在我告诉你什么是递归之前,你应该读一下这篇文章:递归,递归,递归。 如果你没有这么做,那么表扬一下自己。如果你那么...

  • 数据结构-树的遍历

    1. 先序遍历 递归实现 非递归实现 2. 中序遍历 递归实现 非递归实现 3. 后序遍历 递归实现 非递归实现 ...

  • 树的遍历

    节点结构: 先序遍历 递归 非递归 后序遍历 递归 非递归 中序遍历 递归 非递归 层序遍历 类库 有了上述遍历算...

  • 算法图解系列之递归[03]

    3 递归 3.1 递归<函数> 3.2 基线条件和递归条件 3.3 递归调用栈

  • 三十八、递归

    一、递归的概述 递归,指在当前方法内调用自己的这种现象。 递归分为两种,直接递归和间接递归。 直接递归称为方法自身...

网友评论

      本文标题:递归

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