【问题标题】:In recursion, why is this the output在递归中,为什么这是输出
【发布时间】:2022-01-15 06:53:43
【问题描述】:

刚开始学习 javascript,我在学习递归时遇到了这段代码,有人可以帮我解释一下为什么输出是 [1,2,3,4,5] 吗?

function rangeOfNumbers(startNum, endNum) {

  if (endNum - startNum === 0) {
    return [startNum];
  } else {
    var numbers = rangeOfNumbers(startNum, endNum - 1);
    numbers.push(endNum);
    return numbers;
  }
}
console.log(rangeOfNumbers(1,5))

我似乎无法掌握这行代码“var numbers = rangeOfNumbers(startNum, endNum - 1);”

我所知道的是,它会再次调用自己,同时在每次调用 endNum 时减去 1 并将其推送到 numbers 数组中

【问题讨论】:

  • 您忽略了if 部分。
  • endNum 为 5 时,将哪些参数传递给递归调用?该调用将返回什么,numbers 的值将是什么?如果你不能直接弄清楚,你可以通过简单地单独调用相同的调用来测试它。
  • if (endNum - startNum === 0) 很奇怪,这个比较好理解:if (endNum === startNum)
  • 这也是一个很奇怪的递归例子。

标签: javascript recursion


【解决方案1】:

添加日志将帮助您可视化代码中发生的情况。它将向您展示如何进行调用以及使用哪些参数。注意:Stackoverflow 日志没有缩进,所以最好在浏览器的控制台中查看。

function rangeOfNumbers(startNum, endNum) {
  console.group("rangeOfNumbers called with ", startNum, endNum);
  console.log("Subtraction = ", endNum - startNum);
  if (endNum - startNum === 0) { // did we hit the end point?
    console.log("We got zero. Returning ", startNum);
    console.groupEnd();
    return [startNum];
  } else { // numbers are different
    console.log("Calling rangeOfNumbers inside of else");
    var numbers = rangeOfNumbers(startNum, endNum - 1); // Make a new call with end number reduced by one
    console.log("rangeOfNumbers call returned", numbers.join(", "));
    numbers.push(endNum);
    console.log("pushing ", endNum);
    console.log("numbers updated with", numbers.join(", "));
    console.groupEnd();
    return numbers;
  }
}
console.log(rangeOfNumbers(1,5))

【讨论】:

  • 我不建议添加大量的console.logs,而是立即鼓励初学者学习如何使用调试工具。
  • @MaximilianDolbaum 个人意见。我在 24 年前开始构建带有警报的字符串来调试我的 javascript。我能很好地看到它,而不是穿过它。
  • 必须同意这一点,我也更喜欢记录,但调试工具确实是一个强大的敌人,我的所有教授几乎每天都在鼓励它。但你是对的,这是基于意见
  • 昨晚花了 5 个小时在节点中遍历代码检查变量以修复生产中的错误。我们可以很容易地在函数内部设置一个断点并遍历它。问题在哪里这只是递归的一个坏例子。有很多更好的例子。
【解决方案2】:

让我们(暂时)假设rangeOfNumbers(a,b) 产生从ab(包括)的数字列表。

现在您特别询问的部分是有意义的:获取从startNumendNum(含)的数字列表:

  • 计算从startNum但不包括endNum 的数字列表。
  • endNum 添加到该列表的末尾

这留下了我们讨厌的假设:我们的函数只有在较短范围内有效。这就是 if 的用武之地:如果列表仅包含一个值,则返回仅包含该值的列表,无需进行递归调用(这显然应该是正确的)。

这意味着:

  • 该函数适用于长度为 1 的列表(if 代码)
  • 它适用于长度为 2 的列表(通过递归调用长度为 1 的列表,我们刚刚建立了它)。
  • 它适用于长度为 3 的列表(通过递归调用长度为 2 的列表,我们刚刚建立了它)。
  • ...
  • 它适用于长度为 N 的列表(通过递归调用长度为 N-1 的列表,我们刚刚建立了这种方法)。

这意味着它适用于任何可以表示列表长度的 N 值。

【讨论】:

    【解决方案3】:

    我为这些行写了一些 cmets,以便您了解每个行的功能目的,如果您需要更深入地了解发生了什么,请尝试使用 IDE 的调试工具(例如 vscode)。

    在那里你会看到你将进入 else 语句,递归调用函数,再次跳转到 else 和递归,直到你到达第一个 if 中定义的结尾,然后你就完成了对递归和 everz 递归的调用state 将调用下一行你推送数字,然后返回到下一个更高的递归状态。

    所以 1,3 的贯穿:

    3 > 1, => 递归到 2>1, => 递归到 1=1, 中断递归, push 1, step out, push 2, step out, push 3, 然后你就完成了

    function rangeOfNumbers(startNum, endNum) {
    
      if (endNum - startNum === 0) { // This statement checks if the recursion has hit its end when endNum === startNum
        return [startNum]; // This is the point when the recursion is stopped
      } else {
        var numbers = rangeOfNumbers(startNum, endNum - 1); // If the recursion is not finished yet, the function will call itself with the reduced endNum
        numbers.push(endNum); // This is first called in the deepest recursion, so the first one to be added is 1, then it steps back to the recursion state one above and in this case adds the 2 to the array
        return numbers; // Finally we return to be done with the function
      }
    }
    console.log(rangeOfNumbers(1,5)) // This is the start, the function is called with the 2 parameters 1 and 5
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-24
      • 1970-01-01
      • 2012-11-12
      相关资源
      最近更新 更多