简体   繁体   English

如何编写一个递归实例方法来检查一棵二叉树在结构上是否与另一棵二叉树相同?

[英]How to write an recursive instance method to check whether a binary tree is structurally identical to another binary tree?

So today my data structures final had an exam question that asked this: 因此,今天我的数据结构最终有一个考试问题,要求这样做:

"Consider the BinaryTree class and add two recursive methods (independent from each other) named compBT to compare two binary trees. If the two binary trees are structurally identical (ie, they look the same when the objects stored in the nodes are ignored), each of the two methods returns true; otherwise, each returns false. The first method should be an instance method and the second method should be a class method. Do not access the underlying data structure directly. Note: each method should not take more than 6 lines and be properly indented." “考虑BinaryTree类,并添加两个名为compBT的递归方法(彼此独立)以比较两个二进制树。如果两个二进制树在结构上相同(即,当忽略存储在节点中的对象时它们看起来相同),这两个方法都返回true;否则,每个返回false。第一个方法应该是实例方法,第二个方法应该是类方法。不要直接访问基础数据结构。 6行并适当缩进。”

I was able to produce this for the class method: 我能够为class方法生成此代码:

  public static boolean compareTrees(BinaryTree t1, BinaryTree t2) {
      if (t1 == null && t2 == null) return true;
      if ((t1 == null && t2 != null) || (t1 != null && t2 == null)) return false;

      return compareTrees(t1.left, t2.left) && compareTrees(t1.right, t2.right);
  }

I felt pretty confident about this answer, but writing the instance method had me totally stumped, especially since it had to be independent from the class method. 我对这个答案感到非常有信心,但是编写实例方法让我感到很沮丧,特别是因为它必须独立于类方法。 All I was able to produce was the following: 我只能生产以下内容:

public boolean compareTrees(BinaryTree t) {
    if (t == null) return false;
    return (compareTrees(this.left) && (t.left)) && (compareTrees(this.right) && compareTrees(t.right));
}

I know the method is incorrect since it will always return false because there is only one base case which will always be met. 我知道该方法是不正确的,因为它总是会返回false,因为只有一种基本情况会得到满足。 My thought process behind that particular base case is that if the parameter is null, then return false since there is a structural inequality because the caller cannot be null (only non-null references can call instance methods). 在该特定基本情况下,我的思考过程是,如果参数为null,则由于存在调用者不能为null的结构性不平等而返回false(只有非null引用可以调用实例方法)。 But I didn't know what else to do from there. 但是我不知道从那里还能做什么。

Can anyone chime in? 任何人都可以鸣叫吗? I thought this problem was pretty interesting. 我认为这个问题很有趣。

Edit: adding in BinaryTree class. 编辑:添加BinaryTree类。

Here's what the BinaryTree class looked like: 这是BinaryTree类的样子:

class BinaryTree {
    public int value;
    public BinaryTree left;
    public BinaryTree right;

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

I think you've recognized the basic problem. 我认为您已经了解了基本问题。 In your static method, you can pass null for both child trees when you call the method recursively. 在您的静态方法中,递归调用该方法时,两个子树都可以传递null But in your instance method, you can only do that for the parameter. 但是在实例方法中,只能对参数执行此操作。 You can't do that for the instance method, since you can't call an instance method on null . 您无法为实例方法执行此操作,因为您无法在null上调用实例方法。

Well, if you can't call the instance method recursively on a null child, you have to handle the null child case before the recursive call. 好吧,如果您不能在空子对象上递归调用实例方法,则必须在递归调用之前处理空子实例。 That's the key here, the realization that you will have to rearrange your logic. 这就是关键,这是您必须重新安排逻辑的认识。 So your logic will need to be something like this: 因此,您的逻辑将需要像这样:

  1. If the parameter is null, return false (like you already did) 如果参数为null,则返回false(就像您已经做过的那样)

  2. If the instance's left child is null, then: 如果实例的左孩子为空,则:

    2.1 If the parameter's left child is not null, return false 2.1如果参数的左孩子不为null,则返回false

    2.2 If the parameter's left child is null, keep going with step 4 2.2如果参数的左孩子为空,请继续执行步骤4

  3. If the instance's left child is not null, then call recursively on the left child (it doesn't matter if the parameter's left child is null, because that will be caught be #1), and return false if the recursive call returns false 如果实例的左子节点不为null,则对左子节点进行递归调用(该参数的左子节点是否为null无关紧要,因为它将被#1捕获),如果递归调用返回false,则返回false

4-5. 4-5。 Same steps for the right child 对合适的孩子采取相同的步骤

  1. If we've gotten this far, and no check has failed, then we can return true 如果到此为止,并且没有检查失败,那么我们可以返回true

So the code looks something like this: 所以代码看起来像这样:

  public boolean compareTrees(BinaryTree t) {
      if (t == null) return false;
      if (this.left == null) {
          if (t.left != null) {
              return false;
          }
      } 
      else if (!this.left.compareTrees(t.left)) {
          return false;
      }
      if (this.right == null) {
          if (t.right != null) {
              return false;
          }
      } 
      else if (!this.right.compareTrees(t.right)) {
          return false;
      }
      return true;
  }

EDIT: I just now noticed the requirement that the method not be more than 6 lines. 编辑:我刚才注意到该方法不能超过6行的要求。 So I guess my answer won't work. 所以我想我的答案行不通。 On the other hand, I could make it work by compressing a bunch of stuff onto a few lines. 另一方面,我可以通过将一堆东西压缩到几行上来使其工作。

  public boolean compareTrees(BinaryTree t) {
      if (t == null) return false;
      if (this.left == null && t.left != null) return false;
      if (this.left != null && !this.left.compareTrees(t.left)) return false;
      if (this.right == null && t.right != null) return false;
      if (this.right != null && !this.right.compareTrees(t.right)) return false;
      return true;
  }

I could make it even shorter by combining the last two lines into one. 通过将最后两行合并为一个,我可以使其更短。 But if your professor is going to reward compressed, harder-to-read code such as this, and fail cleaner code like I had in my earlier example, shame on him. 但是,如果您的教授将要奖励像这样的压缩的,难以阅读的代码,而使失败的干净代码(如我先前示例中的代码)失败,那就对他感到羞耻。

More: OK, if your professor measures code quality by a smaller number of lines, this should make him ecstatic, even though all my colleagues would blast it in a code review: 更多:好的,如果您的教授用较少的行数来衡量代码质量,即使我的所有同事都会在代码审查中对代码进行爆破,这应该会让他欣喜若狂:

  public boolean compareTrees(BinaryTree t) {
      return !((t == null) || (this.left == null && t.left != null) ||  (this.left != null && !this.left.compareTrees(t.left)) || (this.right == null && t.right != null) || (this.right != null && !this.right.compareTrees(t.right)) );
  }

For instance method, all that changes is that check is before recursion, no in it: 对于实例方法,所有更改仅在于检查在递归之前,其中没有:

  public boolean compareTrees(BinaryTree other) {

      if (left == null) != (other.left == null) return false;
      if (right == null) != (other.right == null) return false;

      if (left != null && !left.compareTrees(other.left)) return false;
      if (right != null && !right.compareTrees(other.right)) return false;

      return true;
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM