用于检查二叉树是否是另一个二叉树的子树的高效算法

时间:2014-08-03 12:04:08

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

鉴于两个二进制树 T1和T2,是否有任何有效的算法来检查T1是否是T2的子树?二叉树是有序标记为,即每个节点都有一个标签,左/右子节点不能交换。

例如,T1:enter image description here是T2的子树:enter image description here

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

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

2 个答案:

答案 0 :(得分:0)

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

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

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

答案 1 :(得分:0)

有一个算法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匹配。