【问题标题】:Why does this program keep on running after null is returned?为什么这个程序在返回 null 后继续运行?
【发布时间】:2015-07-11 17:17:58
【问题描述】:

我正在学习递归,我了解程序的一般工作原理,但我很困惑为什么在第一次返回 null 后程序继续工作,而值 16 太大了。

基本上,下面的代码将运行并从 1、6、11 到 16 每次将 5 添加到 start 参数。由于 16 > 13,它表示返回 null。当 JavaScript 在第 6 行只说 return null 时,它怎么知道要返回并尝试计算 13?

非常感谢任何帮助。这是我正在看的书中的代码:

function findSolution(target) {
  function find(start, history) {
    if (start == target)
      return history;
    else if (start > target)
      return null;
    else
      return find(start + 5, "(" + history + " + 5)") ||
             find(start * 3, "(" + history + " * 3)");
  }
  return find(1, "1");
}

console.log(findSolution(13)); 

【问题讨论】:

  • 明确地说,它工作得很好,你只是问它是如何工作的

标签: javascript recursion null


【解决方案1】:

罪魁祸首是:

  return find(start + 5, "(" + history + " + 5)") ||
         find(start * 3, "(" + history + " * 3)");

假设 start 等于 1,并且与您的代码一样,我们的目标是 13。

  1. find() 以我们的 1 开头。让我们称之为Find A
  2. find() 到达上面的 sn-p 并使用新的 start1 + 5 (6) 再次触发。我们称之为Find B
  3. Find B 也到达上面的 sn-p 并被新的 start6 + 5 (11) 再次触发。我们称之为Find C
  4. Find C 也到达上面的 sn-p 并被新的 start11 + 5 (16) 再次触发。我们称之为Find D
  5. Find D 将值null 返回给Find C
  6. Find C 执行上述sn-p 的OR 参数。 find() 被新的start6 * 3 (18) 再次触发。我们称之为Find E

看看发生了什么?

  1. Find E,就像我们已故的朋友 Find D 返回值 nullFind C
  2. Find C 现在返回值nullFind B
  3. Find B执行上述sn-p的OR参数。

最终,当null 以外的值返回到您原来的Find A 调用时,您的递归将结束,但在到达原来的Find A 之前还有一段路要走 最后返回一个值给我们的findSolution() 函数。

对于每个null 响应,都会进行一个新的find() 调用。 null 是一个虚假值。直到返回一个真实值(在这种情况下是您的 history 变量),新的 find() 函数将被执行。当history 变量返回时,它会被传回调用函数,调用函数将其传回其调用函数,直到最终将其返回给我们的 Find A 函数调用,该函数调用将其传回到findSolution() 函数。


工作可视化

您需要为此打开 JavaScript 控制台。

var findIteration = 0;

function findSolution(target) {
  function find(start, history, caller) {
    var thisIteration = ++findIteration;
    console.log("Find Iteration " + thisIteration, "Start: " + start, "Called by: " + caller);
    if (start == target)
      return history;
    else if (start > target)
      return null;
    else
      return find(start + 5, "(" + history + " + 5)", thisIteration) ||
             find(start * 3, "(" + history + " * 3)", thisIteration);
  }
  return find(1, "1", 0);
}

console.log(findSolution(13));

这是我们的控制台输出的样子:

这里的“调用者”是调用它的 find() 方法——就像 Find C(迭代 3)如何调用 Find E(迭代 5)我在开始时给出的文本示例。

总而言之,我们的 find() 函数在最终达到正确值之前被分别调用了 9 次。

【讨论】:

  • @James_Donnelly 感谢您的帮助。只有一件事我还是不明白。这段代码如何修改调用者?我没看到你说要在哪里改变它。
  • 感谢您的帮助。只有一件事我还是不明白。这段代码如何修改调用者?我没看到你说要改变它
  • @Gwater17 “改变它”是什么意思?你想改变什么?
  • 我不想改变任何东西。我只是不明白每次函数运行时调用者的值是如何改变的。你永远不会说给调用者加 1 或减 1 或其他什么
  • @Gwater17 你不需要。该函数调用自身,这意味着该函数执行多次。如果为空,则函数调用自身。如果它调用的函数为空,它也会调用它自己。只有当其中一个函数不为空时,它才会冒泡回到原来的函数并返回一个值。
【解决方案2】:

查看代码 - 它在 a fiddle 中工作:

return find(start + 5, "(" + history + " + 5)") ||
             find(start * 3, "(" + history + " * 3)");

这基本上是检查第一个调用与 find() 并通过|| 或比较进行第二个调用。当函数returns null。 Javascript null 在逻辑或运算中被视为 false。所以当两个 find() 调用都返回 null 时,递归将停止。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-09
    • 1970-01-01
    • 1970-01-01
    • 2018-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多