递归以及递归过程分析

递归

递归:就是在函数运行过程中调用自己。

简单的说,递归就像是平时查字典,当你遇到了一个问题 “词A是什么意思?”,你去查了字典,但是你发现字典的解释中有一个词B你不理解,因此你又一次拿起字典查词B,终于在多次查词之后,你没有再碰到不理解的词,于是你倒回去理解了所有词的意思,并解决了一开始的问题“A 是是什么意思?”

在这个过程中,字典就像是递归函数,递归终止条件就是没有再遇到不理解的词。

递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。

递归的要素

从上面的例子可以看出,递归有两个要素:

  1. 找到重复的逻辑(不认识的词),不断缩小问题规模。
  2. 明确递归终止的条件(没有不认识的词)。

递归存在两个过程:前行阶段和回退阶段。

  1. 在前行阶段,调用递归函数,会形成一个栈。
  2. 在回退阶段,会根据前行阶段形成的栈进行出栈。

利用斐波那契理解递归

function factorial(number)
{
  if (number == 1)
  {
  	return number;
  }
  else
  {
  	return number * factorial(number-1);
  }
}
factorial(5)  //120

上面代码的两个要素分别是:

  1. 终止条件:
    if (number == 1)
    {
    return number;
    }
  2. 重复的逻辑:
    number * factorial(number-1);

接下来我们分析一下,递归解决斐波那契函数的具体过程:

  1. 前行过程:

    在终止条件处,程序知道了 factorial(1) = 1,并不再继续调用自身,于是前行阶段结束,进入回退阶段。

  2. 回退阶段:

    在回退阶段,程序会执行在前行阶段没有执行的代码 number * factorial(number-1);

利用二叉树的遍历理解递归

假设我们需要对如下二叉搜索树进行中序遍历:

二叉搜索树中序遍历部分代码如下:
完整代码

this.inOrder = function(curNode)
{
    if(curNode !== null)
    {
        this.inOrder(curNode.left);
        console.log(curNode.val);
        this.inOrder(curNode.right);
    }
}

在递归过程中,程序会把访问过的结点压入堆栈,如:this.inOrder(curNode.left);会把curNode的左孩子压入栈。
因为我们调用中序遍历时首先是tree.inOrder(tree.root),因此根结点入栈。
接着在函数中自己调用自己this.inOrder(curNode.left);,左子树的根结点依次入栈。
this.inOrder(curNode.left);的前行阶段结束时(结束条件是curNode.left === null),会形成以下栈:

接下来前行阶段结束,继续执行其他代码,首先打印出结点3,之后执行this.inOrder(3.right);但是因为结点3没有右子树,因此直接碰到终止条件(this.inOrder(3.right);访问了null结点,因此按照访问的结点都要入栈的规则,把null结点入栈,但因为null结点碰到了终止条件,因此不再调用递归,因此很快执行完成,执行完成之后把null结点出栈),因此继续执行其他代码,发现结点3的函数执行完成,把结点3弹出栈。
接下来,对结点16继续执行代码console.log(curNode.val);因此打印出结点16,接下来继续执行this.inOrder(16.right);,因为这个也是一个递归,因此会形成一个新的栈。

当执行到this.inOrder(19.left);时,因为结点19没有左子树,因此碰到终止条件,开始进入回退阶段,继续执行结点19的代码,打印出结点19,并检查this.inOrder(19.right);,因为结点19没有右子树,因此结点19的代码执行完成,把结点19出栈。
接下来执行结点22的代码,打印出结点22之后再执行this.inOrder(22.right);,因为结点22的右子树不为null,因此又一次调用自身,形成另一个栈:
在这里插入图片描述
接下来执行this.inOrder(24.left);,因为没有左子树,所以继续执行console.log(24.val);打印出结点24,之后接着执行this.inOrder(24.right);,因为没有右子树,所以结点24的代码执行完成,把24出栈,这时栈空了,说明结点22的右子树遍历完成,回到结点22的代码,因为结点22的代码执行完成,把结点22出栈,这时栈空了,说明结点16的右子树遍历完成,回到结点16的代码。(之后的过程也和上面差不多)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值