理解递归后的执行 - 递归如何确定何时停止?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了理解递归后的执行 - 递归如何确定何时停止?相关的知识,希望对你有一定的参考价值。

我知道这里有许多递归线程。从技术上讲,我确实理解递归背后的原理,我只是对存储实际递归计数器的位置或者编译器如何跟踪它更加好奇

代码可能更好地理解这一点。我在javascript中创建了一个简单的递归函数。

function factorial(number){
    if (number > 1) {
    return number * factorial(number - 1);
  } else {
    return number;
  }
}

现在,每个人都明白这是如何运作的。我们在factorial上调用递归函数,递归重复直到函数结束。

我的问题是,为什么阶乘函数会在正确的时间停止执行递归?如果我们试图在我们的脑海中调试函数,我的理解是,它看起来像这样:

假设我们打电话给factorial(3);

  1. 调用的函数 - >加载参数
  2. 计算IF条件 - > 3> 1 - >应用递归函数
  3. 3 *递归(2)*递归(1)=> 3 * 2 * 1 = 6

现在我的问题是,这怎么可能? a)如果我们将递归计数器减少到1,我们没有输入else {语句,因为它应该被评估为false,而b)递归计数器怎么知道,循环递归函数只有数量-Nth of amount次?

为了更好地说明,我添加了以下代码行document.write("entered with number " + number + "</br>");,因此我们将在每次输入if条件时将其打印出来。

function factorial(number){
	if (number > 1) {
  	document.write("entered with number " + number + "</br>");
  	return number * factorial(number - 1);
  } else {
  	return number;
  }
}

document.write(factorial(3) + "<br/>");

正如你所看到的,if条件如果条件被评估为真并且打印出3和2的消息。为什么计数器没有循环低,如果我们在else { return number; }上调用递归操作,我们怎么也不会返回到初始的factorial(2-1)

这是一个相当困难的问题,所以如果您对如何更好地表达它有任何想法,请随时编辑我的问题!

答案

这里有一个关于递归正在做什么的口头描述,太详细了:

  1. 你在factorial(3)中打电话给document.write()
  2. factorial(3)想要返回3 * factorial(2)。在它返回一个值之前,它必须弄清楚factorial(2)的意思。
  3. 所以现在我们有factorial(3)等待factorial(2)的结果。 factorial(2)运行,并希望返回2 * factorial(1)。在它返回一个值之前,它必须解决factorial(1)的含义。
  4. 现在我们有factorial(3)等待factorial(2)的结果,等待factorial(1)的结果。 factorial(1)运行,并且看到它的输入是1,所以命中“else”块,所以只返回1给它的调用者factorial(2)
  5. 现在factorial(2)有它需要的东西,所以可以将2 * 1返回给它的来电者factorial(3)
  6. 现在factorial(3)有它需要的东西,所以可以将3 * 2返回给它的来电者。
  7. 呼叫document.write收到“6”。

递归“知道”停止的位置,因为它最终会到达一个只返回数字1的点,而不是返回依赖于对factorial()的另一个调用的东西。如果函数总是试图调用自己,那么就没有办法摆脱递归循环;它会一直持续到堆栈溢出。

除了factorial(1)之外,每次调用factorial(n)最终都会调用factorial(n-1) - 所以请注意factorial(0)factorial(-1)factorial(1.01)永远不会达到1,所以递归将继续运行直到堆栈溢出。在编写递归函数时,最好注意并处理永远不会到达出口点的输入;在这种情况下,如果输入不是正整数,则您想要抛出错误。

为什么计数器没有循环降低,为什么我们永远不会回到最初的其他地方{返回号码;如果我们在factorial(2-1)上调用递归操作?

它确实如此,但你在函数内的document.writeif块内部,所以当函数进入else块时没有打印出来。这是相同功能的更详细版本,可以让您更清楚地了解发生的情况:

function factorial(number) {
  document.write("entered with number " + number + "<br>");
  if (number > 1) {
    document.write("recursing<br>")
    return number * factorial(number - 1);
  } else {
    document.write("Returning 1<br>")
    return number;
  }
}

document.write(factorial(3) + "<br>");

以上是关于理解递归后的执行 - 递归如何确定何时停止?的主要内容,如果未能解决你的问题,请参考以下文章

如何真正的理解递归?

递归Recursion

在递归方法中如何知道我的所有线程何时完成执行?

如何确定一种语言是递归的还是递归可枚举的?

递归算法

如何在没有转义序列的情况下停止递归