【问题标题】:Are recursive calls made in a conditional statement?递归调用是在条件语句中进行的吗?
【发布时间】:2020-10-01 16:38:52
【问题描述】:

我正在尝试遍历以下递归代码以查找二叉树的深度,但不知道是否调用了条件中的递归调用:

var maxDepth = function (root) {
  return maxDepthHandler(root, 1);
};

var maxDepthHandler = function (root, depth) {
  if (!root) {
    return 0;
  }
  if (!root.right && !root.left) {
    return depth;
  }
  if (root.right && root.left) {
    // are these recursive functions called when checking the condition?
    if (
      maxDepthHandler(root.right, depth + 1) >
      maxDepthHandler(root.left, depth + 1)
    ) {
      return maxDepthHandler(root.right, depth + 1);
    } else {
      // for my follow up question: is this the first recursive call?
      return maxDepthHandler(root.left, depth + 1);
    }
  } else if (root.right !== null) {
    return maxDepthHandler(root.right, depth + 1);
  } else {
    return maxDepthHandler(root.left, depth + 1);
  }
};

给定下图:

        13
       /  \
      8    37
     / \   / \
    6  11 24 42

如果递归调用没有在条件语句中调用,这是否意味着运行 maxDepth(13) 将导致 maxDepthHandler(root.left, depth + 1); 成为第一个递归调用?我认为这是因为在第一次调用时,如果没有调用条件中的递归调用,则无法计算条件,因此运行 else 语句。

【问题讨论】:

    标签: algorithm recursion conditional-statements binary-tree depth


    【解决方案1】:

    是的,它们被调用,因为需要它们的值来确定是否进入 if 语句体。

    【讨论】:

      【解决方案2】:

      在您的具体情况下,它们都被调用。这意味着您可能应该捕获它们的值以避免重复努力:

      let right = maxDepthHandler(root.right, depth + 1);
      let left = maxDepthHandler(root.left, depth + 1);
      if (right > left) {
        return right;
      } else {
        return left;
      }
      

      或:

      let right = maxDepthHandler(root.right, depth + 1);
      let left = maxDepthHandler(root.left, depth + 1);
      return right > left ? right : left;
      

      或:

      let right = maxDepthHandler(root.right, depth + 1);
      let left = maxDepthHandler(root.left, depth + 1);
      return Math.max(left, right);
      

      或:

      return Math.max(maxDepthHandler(root.left, depth + 1), maxDepthHandler(root.right, depth + 1));
      

      附带说明,因为您通过返回 0 来处理 null root 的情况,我认为如果您的整个函数变为:

        if (!root) {
          return 0;
        }
        return Math.max(maxDepthHandler(root.left, depth + 1), maxDepthHandler(root.right, depth + 1));
      

      但是,在某些情况下,条件语句中的函数调用不会被调用。例如:

      if(foo(1) || foo(2)) {
      ...
      }
      if(foo(3) && foo(4)) {
      ...
      }
      

      在本例中,如果foo(1) 返回true,则|| 运算符将短路 而不会打扰调用foo(2)。如果foo(3) 返回false,则&& 运算符将短路,因此不会调用foo(4)

      【讨论】:

      • 您描述的短路是不需要的行为,对吗?意味着应该避免以这种格式编码递归函数吗?我没有捕获每个值,因为我需要递归调用 maxDepthHandler 直到我达到基本情况(不在我的问题中,因为它与我的问题无关)。
      • @boxcarcoder:我实际上在第一次迭代中犯了一个逻辑错误,并纠正了它。一般的答案是:这取决于递归函数的目的。例如,如果目的是查找给定值是否存在于结构中,并且如果在结构的一部分中找到该值,则该函数仅返回true,您可能会说return find(value, root.left) || find(value, root.right)find(..., root.right) 如果已经在左侧找到值,则不调用它会很好,不是吗?
      • @boxcarcoder:在捕获值时,您仍然会递归调用它,直到达到基本情况。这只是意味着您不会将整个事情重复两次。您只需访问每个节点一次,而不是全部访问两次。
      猜你喜欢
      • 2020-01-04
      • 2019-03-20
      • 2018-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-12
      • 1970-01-01
      相关资源
      最近更新 更多