【问题标题】:How to find if two binary trees are identical in terms of content?如何判断两棵二叉树的内容是否相同?
【发布时间】:2017-05-23 19:46:29
【问题描述】:

我看到几篇关于如何确定两棵树的结构是否相同的帖子,但没有找到任何关于如何确定两棵树的内容是否相同的答案。

说,树节点定义如下。

TreeNode {
    string data;
    TreeNode* left;
    TreeNode* right
};

现在我有两棵二叉树,需要找出两棵树的内容是否相同。这两者在结构上可能不完全相同,我们也不能假设数据字符串在单词上是相同的。

例如,我们可能有以下两棵树。当我们进行 inorder walk 时,这两棵树在内容上可以被视为相同。需要明确的是,当我们连接这两个树中的所有节点字符串时,它们是相同的。即 abcdedfg

 (abc)
 |   \
 (d) (efg)

 (a)
 |  \
 (b) (cdefg)

我知道我们可以进行 inorder walk 来收集两棵树的所有字符串,我们可以比较生成的两个字符串,但我想知道是否有更有效的方法来比较两棵树,或者以某种方式走两棵树并行或创建迭代器。这些对我来说似乎都不是很明显,所以想获得一些反馈,也许还有一些代码 sn-p 以获得更好的想法。

提前致谢。

【问题讨论】:

  • 我会按照你说的顺序走,但是比较直到你找到 2 个不同的元素。这在最坏的情况下具有 min(n,m) 时间复杂度,因此是可能的最快算法。
  • 感谢您的评论。我刚刚更新了我的问题。如果您可以提供一些代码示例,将会很有帮助。 ;-)
  • 是的,请参阅我在 python 中的完整代码的答案,它使用生成器使其更快。
  • 抱歉,您是说示例中的两棵树是否相等?
  • 你是如何得到这个特殊结构的,具体来说,每个节点中都有 >1 个字符?什么决定了给定节点中是否有 2 3 4 5 .. 字符?我建议,如果您将结构标准化 - 每个节点一个字符,您将获得更有效的解决方案。但同样,它不清楚上下文是什么。

标签: algorithm binary-tree


【解决方案1】:

您可以使用 DFS(深度优先搜索)逐个字符地比较两棵树。这也将与双指算法相结合,您可以根据您要处理的元素以不同的速度遍历每棵树的节点。

从你的例子。树 1 和树,其中节点 X-Y 是行 X,元素 Y。树 1 节点 2-2 是“efg”:

Tree 1
(abc)
 |   \
 (d) (efg)

Tree 2
 (a)
 |  \
 (b) (cdefg)

算法会依次遍历每棵树的节点,逐个字符进行比较。

  1. 树 1 节点 1-1 开始
  2. 树 2 节点 1-1 开始
  3. 比较 a1 和 a2
  4. 前进到树 2 节点 2-1
  5. 比较 b1 和 b2
  6. 前进到树 2 节点 2-2
  7. 比较 c1 和 c2
  8. 前进到树 1 节点 2-1
  9. 比较 d1 和 d2
  10. 前进到树 1 节点 2-2
  11. 比较 e1 和 e2
  12. 比较 f1 和 f2
  13. 比较 g1 和 g2
  14. 返回相同!

【讨论】:

  • 感谢您的回答。对,这就是我想要完成的,但找不到任何简单的方法来编写代码。也许 Piotr 的回答是这样做的,但我不清楚它是否这样做,所以要求澄清。
  • Piotr 的回答非常好,符合我的算法。他使用 Python 迭代器来允许您在完全隐藏底层树结构的同时迭代字母。然后比较两棵树的函数只是遍历两个迭代器并确保它们相同。您更喜欢哪种语言的答案?
【解决方案2】:

解决方案是编写生成器,从排序的元素中一一生成字母。这比一次生成所有字母要快,因为例如可以检测到树与第一个字母不同,在这种情况下它不会比较剩余的字母。在 Python 中,这将是:

def iter_bin_tree_letters(tree):
    if tree.left:
        for letter in iter_bin_tree_letters(tree.left)
            yield letter
    # RETURN ITERATOR OVER LETTERS  <----------
    for letter in tree.data:
        yield letter
    if tree.right:
        for letter in iter_bin_tree_letters(tree.right)
            yield letter

现在只需比较两个生成器的结果,直到找到 2 个不同的元素或用完元素:

def are_equal_bin_trees(tree1, tree2):
    t1 = iter_bin_tree_letters(tree1)
    t2 = iter_bin_tree_letters(tree2)
    t1_empty = False
    while True:
        try:
            e1 = t1.next()
        except:
            t1_empty = True
        try:
            e2 = t2.next()
        except:
           if not t1_empty:
               return False
           return True
        if e1!=e2:
             return False

这是最快的算法,在最坏的情况下它的时间复杂度为 min(n,m)。

【讨论】:

  • 谢谢,我不懂python。好吧,对我来说它看起来像 python ;-) 。快速提问。您的代码是否处理我的示例案例?第一棵树的第一个节点返回“abc”,而第二棵树的第一个节点只返回“a”。当我们连接时,两个字符串变得相同,但每个节点字符串可能不同。
  • 逐个节点比较。我不连接任何东西。在您的示例案例中,它首先比较 b 和 d 并检测它们不同,因此它返回 False。如果它们相同,它将继续比较“a”和“abc”等等。
  • 感谢 Piotr 的澄清。也许不清楚,但想找到方法来比较整个内容,而不仅仅是逐个节点比较。
  • 抱歉,我没有正确阅读。稍等我修改一下,加上cmets,思路一样。
  • 好的,我修改了代码,现在它适用于你的情况,并且速度尽可能快:) 你应该能够理解这段代码,但如有任何问题,请询问
【解决方案3】:

您似乎必须枚举两棵树中的所有节点以查看它们是否具有不同的内容。

除非遍历树中的所有节点,否则不可能知道节点是否在树中。例如

 a      a
b c    c d

您在两次传递中看到abac。您不知道树 1 是否包含 c 或树 2 是否包含 b,除非您遍历两棵树的全部。

当您迭代时,您可以将每个节点放在一个单独的优先级队列中,并从队列顶部弹出值,直到您弹出的值不相等。对于树中每个节点的 log(n) 插入的启发式开销,这使您的平均情况比使用普通队列快得多。

【讨论】:

    【解决方案4】:

    散列两个数据结构或使用简单的 o(n) 算法比较它们。每个数据结构都可以表示为字节流。是的,在这种情况下使用指针是个问题,应该避免。

    我假设这些树是由相同的算法生成的,所以不可能有两个不同的树具有相同的内容。

    【讨论】:

      【解决方案5】:

      我们可以首先将两棵树的遍历存储在数组中 - 成本 O(n) 现在我们遍历两个数组并对所有元素进行异或,如果异或 为零,则它们相同,否则不相同-成本 O(n) 所以我们可以在 O(n) 中做。

      【讨论】:

        猜你喜欢
        • 2021-08-01
        • 1970-01-01
        • 2021-11-24
        • 2013-07-03
        • 1970-01-01
        • 2010-10-19
        • 1970-01-01
        • 1970-01-01
        • 2018-06-30
        相关资源
        最近更新 更多