递归

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

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

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;
}
这个函数与前面的递归函数求值是一样的,但是在函数逻辑上面差别非常大。
在递归函数里面,运用了一部分的数学逻辑在里面,能清晰看见数学等式,而非递归实现里面数学逻辑其实是隐藏起来的,是编码人员在知道数学逻辑的情况下实现,而没有体现在代码层面上。这样在数学逻辑变动的时候,维护起来是不太好的。
如果递归不能让你的代码变得清晰,你自己看代码也会迷惑,那就不要生硬得用递归了。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值