【问题标题】:Efficient algorithms for checking if a binary-tree is a subtree of another binary-tree检查二叉树是否是另一棵二叉树的子树的有效算法
【发布时间】:2014-08-03 12:04:08
【问题描述】:

给定两个 二叉树 T1 和 T2,是否有任何有效的算法来检查 T1 是否是 T2 的 子树?二叉树是 orderedlabeled,即每个节点都有一个标签,并且左/右子节点不能交换。

例如,T1: 是 T2: 的子树

简单的算法在 O(|T1| * |T2|) 中运行,只需遍历 T2 的每个节点并检查 T1 是否可以在该节点匹配。

O(|T1| + |T2|) 可能吗?

【问题讨论】:

  • 您可能会在计算机科学 stackexchange 网站上获得更好的答案:cs.stackexchange.com

标签: algorithm data-structures tree pattern-matching binary-tree


【解决方案1】:

子树(C, (D), (B)) 由两个向上的链接D-(L)>C 和B-(R)>C 组成,其中L 和R 区分左右链接。任何具有 n 个叶子的子树都由 n 个向上的序列组成,每个序列都从一个叶子开始,到子树的根结束,该序列记录节点的字母和它向上移动的链接的左或右性质。

构建一个http://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_string_matching_algorithm 字符串匹配器来识别这些序列,并在从叶子开始到根结束的较大树的路径上运行它。

当找到 Aho-Corasick 匹配时,在匹配它的序列的最高节点上标记匹配以及它是哪种匹配。如果您找到较大树的一个节点,该节点累积了您在 Aho-Corasick 匹配器中构建的每个模式的集合,则此节点是您尝试查找的较小子树副本的根。

【讨论】:

  • 我猜这个方法也是O(|T1| * |T2|)?
  • 构造一个大小为 n 的 Aho-Corasick 树是 O(n)。根据这棵树检查文本的 n 个字符是 O(n + 找到的匹配数)。在大多数情况下,我希望它在实践中是 O(|T1| + |T2|)。可能有一些退化的情况需要小心 - 如果较大的树非常高,叶子很少,如果你从所有叶子一直向上搜索,你会重复自己 - 你可能会记下 Aho-Corasick 的状态如果你在同一个地方处于相同的状态,那么你去的时候就停止匹配器。
【解决方案2】:

有一个O(kT1+T2)的算法,首先遍历T2找到所有值等于T1的根值的节点,假设我们有k个这样的节点,这个T2的遍历需要O(T2)。然后对于这些节点中的每一个,检查它是否与 T1 匹配,这需要 O(kT1)。如果 T2 是唯一的或者只有一个节点等于 T1 的根,则复杂度正好是 O(T1+T2)。在T2中查找T1的根节点的代码是这样的:

void do_find_nodes(node* root, T value, std::vector<node *>& nodes)
{
    if(root)
    {
        if(root->val == value)
            nodes.push_back(root);
        do_find_nodes(root->left);
        do_find_nodes(root->right);
    }
}
void find_nodes(node *root, T value)
{
    std::vector<node *> nodes;
    do_find_nodes(root, value, nodes);
}

调用 find_nodes() 将为您提供 T2 中的所有节点,其值等于 T1 的根,然后您可以检查每个节点是否与 T1 匹配。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-20
    • 1970-01-01
    • 2021-08-24
    • 2021-03-30
    • 1970-01-01
    • 2014-09-24
    • 1970-01-01
    • 2015-04-23
    相关资源
    最近更新 更多