递归

来源:互联网 发布:狗爹怎么解析域名 编辑:程序博客网 时间:2024/06/03 19:20

         开始讨论递归前需要知道递归的两个特性:存在限制条件,当符合这个条件时,递归便不再继续;每次递归调用后越来越接近这个限制条件。

         当一个问题相当复杂,难以用迭代形式实现时,此时递归的简洁性便可以补偿它所带来运行时的开销。

https://www.zhihu.com/question/31412436,转自知乎,如侵权联系我

1、在用递归的时候,当成一个黑盒子,不要老是想着递归这着方法,而是只是把递归函数当成一个普通的调用函数,对这个函数,你需要知道他的输入与输出。

2、将递归一步步展开可以理解递归。

3、可以类比数学归纳法…

第一步:先检查退出条件是否正确,这相当于归纳法中的初值f(0)。
第二步:假设在递归函数中被调用的函数自身返回成功,看递归函数是否正确,这相当于归纳法中从 f (k-1)到f(k)的过程。
这个方法不但有助于理解分析递归函数,也有助于编写递归函数。比如最简单的n的阶乘的递归实现,代码如下。

function factorial (n) {
  if (n === 1) {
    return n;
  } else {
    return n * factorial(n-1);
  }
}
你在写这个函数的时候,把函数定义部分代码蒙起来,主要看这部分代码
  if (n === 1) { // 如果求1的阶乘,那么就直接返回
    return n;
  } else { // n! = n * (n-1)! 这个数学等式
    return n * factorial(n-1);
  }
那这样看代码,你懂了吗?
如果你觉得还不懂的话,且听我下面说完。
不说性能上面的影响,递归的使用能让你的代码变得简单清晰,逻辑变得易懂,就比如下面这段代码,用非递归的方式实现阶乘。
function factorial (n) {
  var result = 1;
  for (var i = n; i > 0; i--) {
    result *= i;
  }
  return result;
}
这个函数与前面的递归函数求值是一样的,但是在函数逻辑上面差别非常大。
在递归函数里面,运用了一部分的数学逻辑在里面,能清晰看见数学等式,而非递归实现里面数学逻辑其实是隐藏起来的,是编码人员在知道数学逻辑的情况下实现,而没有体现在代码层面上。这样在数学逻辑变动的时候,维护起来是不太好的。
如果递归不能让你的代码变得清晰,你自己看代码也会迷惑,那就不要生硬得用递归了。

        递归隐式地使用了一个数据结构来存放调用栈上的数据。这意味着应该有一个等价的显示栈来避免使用递归解决方案。例如二叉树的前序遍历,递归调用用于在隐式的栈上存储右子树的地址,因此可以在左子树遍历完成后,可以继续遍历右子树,因此从一个递归的调用中返回,实际上是从隐式的栈上弹出右子树节点的地址,这样就可以继续的遍历。

0 0
原创粉丝点击