【问题标题】:Finding if a value is contained in a binary tree查找值是否包含在二叉树中
【发布时间】:2019-03-11 12:18:49
【问题描述】:

我有一个类 TreeNode 如下所示:

class TreeNode {
    int value;
    TreeNode left;
    TreeNode right;

public TreeNode(int x) {
    value = x;
}

我想编写一个递归方法 contains(int i),如果 i 是树中节点的值,则返回 true,否则返回 false。

根据我的理解,二叉树不一定是有序的,所以我不应该将当前节点的值与我们正在搜索的值进行比较。因此我写了以下方法:

public boolean contains(int i) {
    if (value == x) {
        return true;
    } else {
        if (left != null) {
            return left.find(i);
        }
        if (right != null) {
            return right.find(i);
        }
    }
    return false;
}

我的想法是它会检查当前节点的值是否等于我们正在搜索的值,如果不等于,那么它应该递归调用左右节点的方法,如果它们不为空,否则该方法将返回false。

如果我们正在搜索与树左侧节点对应的值,此方法最终返回 true,但是一旦我们搜索超出此值(向右)的值,它将返回 false。我已经为此思考了好几个小时,我确信有一个相对简单的解决方案,但我似乎无法解决。

【问题讨论】:

    标签: algorithm tree


    【解决方案1】:

    类似这样的:

    public boolean contains(int i) {
        return value == i ||
           left != null && left.contains(i) ||
           right != null && right.contains(i);
    }
    

    【讨论】:

    • 非常简洁;由于 || 运算符的延迟评估,它还被优化为提前中断。但是,对于初学者来说可能很难阅读。
    • NPE 可以扔在这里。
    【解决方案2】:

    不先检查是true还是false就返回递归调用的结果是不正确的。

    如果左子树搜索返回false,您仍应搜索右子树。

    public boolean contains(int i) {
        if (value == x) {
            return true;
        } else {
            boolean found = false;
            if (left != null) {
                found = left.find(i);
            }
            if (!found && right != null) {
                found right.find(i);
            }
            return found;
        }
    }
    

    【讨论】:

      【解决方案3】:

      这似乎更正确:

      public boolean contains(int i) {
          if (value == x) {
              return true;
          } else {
              if (left != null && left.find(i)) {
                  return true;
              }
              if (right != null && right.find(i)) {
                  return true;
              }
          }
          return false;
      }
      

      【讨论】:

        【解决方案4】:
            if (left != null) {
                return left.find(i);
            }
        

        这就是问题所在。如果同时存在左节点和右节点,则代码将仅返回是否在左侧找到任何内容。

        相反,你想要的是:

            boolean found = false;
            if (left != null) {
                found = left.find(i);
            }
            if (!found && right != null) {
                found = right.find(i);
            }
            return found;
        

        【讨论】:

          【解决方案5】:

          您的实现更喜欢左子树;它没有在两个子树中正确搜索。这可以通过以下方式修复。

          public boolean contains(int i) {
              boolean Result = value == x;
              if (left != null) {
                  Result |= left.find(i);
              }
              if (right != null) {
                  Result |= right.find(i);
              }
              return Result;
          }
          

          这个实现可以进一步优化如下,提前返回。

          public boolean contains(int i) {
              boolean Result = value == x;
              if (!Result && left != null) {
                  Result |= left.find(i);
              }
              if (!Result && right != null) {
                  Result |= right.find(i);
              }
              return Result;
          }
          

          【讨论】:

            【解决方案6】:

            您的代码似乎无法编译,因为 TreeNode 类没有 find(int i) 方法。

            我认为contains() 方法应该看起来像:

            public boolean contains(TreeNode node, int i) {
              boolean result = node.value == i;
              if (left != null) result |= contains(node.left, i);
              if (right != null) result |= contains(node.right, i);
              return result;
            }
            

            当然,您可以在找到值后终止并跳过两个!= null 检查,方法是在方法的开头添加一个额外的递归底部:

            public boolean contains(TreeNode node, int i) {
              if (node == null) return false;
              if (node.value == i) return true;
              return contains(node.left, i) || contains(node.right, i);
            }
            

            可以进一步简化为单行:

            public boolean contains(TreeNode node, int i) {
              return node != null && 
                    (node.value == i || contains(node.left, i) || contains(node.right, i));
            }
            

            【讨论】:

            • 抱歉,如果不清楚 - contains 方法在 TreeNode 类中运行。感谢您的回复。
            • @anndumpster,不过,您仍然可以按照我建议的方法进行操作。 :) 唯一的区别是您不需要将 TreeNode 参数传递给 contains() 方法。
            【解决方案7】:

            虽然,我宁愿创建第二个静态方法,其参数为 TreeNode 和 int,但您的方法的正确修复是这样的:

            public boolean contains(int i) {
                if (value == x) {
                    return true;
                }
            
                if (left != null && left.find(i)) {
                    return true;
                }
                if (right != null && right.find(i)) {
                    return true;
                }
            
                return false;
            }
            

            如果左子树不包含该值,则代码中的错误是您没有给右子树机会。如果您不确定没有任何其他结果,请不要返回值。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2012-06-05
              • 1970-01-01
              • 2015-04-23
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-05-16
              相关资源
              最近更新 更多