一种简单的方法是为树编写 is_equal() 方法并执行以下操作,
bool contains_subtree(TNode*other) {
// optimization
if(nchildren < other->nchildren) return false;
if(height < other->height) return false;
// go for real check
return is_equal(other) || (left != NULL && left->contains_subtree(other)) || (right != NULL && right->contains_subtree(other));
}
注意 is_equal() 可以通过对树使用哈希码来优化。它可以通过将树的高度或子节点的数量或值的范围作为哈希码以简单的方式完成。
bool is_equal(TNode*other) {
if(x != other->x) return false;
if(height != other->height) return false;
if(nchildren != other->nchildren) return false;
if(hashcode() != other->hashcode()) return false;
// do other checking for example check if the children are equal ..
}
当树类似于链表时,需要 O(n) 时间。我们还可以在选择要比较的孩子时使用一些启发式方法。
bool contains_subtree(TNode*other) {
// optimization
if(nchildren < other->nchildren) return false;
if(height < other->height) return false;
// go for real check
if(is_equal(other)) return true;
if(left == NULL || right == NULL) {
return (left != NULL && left->contains_subtree(other)) || (right != NULL && right->contains_subtree(other));
}
if(left->nchildren < right->nchildren) { // find in smaller child tree first
return (left->contains_subtree(other)) || right->contains_subtree(other);
} else {
return (right->contains_subtree(other)) || left->contains_subtree(other);
}
}
另一种方法是将两个树序列化为字符串并查找第二个字符串(从 T2 序列化)是否是第一个字符串(从 T1 序列化)的子字符串。
以下代码在预购中序列化。
void serialize(ostream&strm) {
strm << x << '(';
if(left)
left->serialize(strm);
strm << ',';
if(right)
right->serialize(strm);
strm << ')';
}
并且我们可以使用一些优化的算法,例如Knuth–Morris–Pratt algorithm 来查找(可能在 O(n) 时间内)子字符串的存在,并最终找出一棵树是否是 other 的子树。
再次使用 Burrows–Wheeler_transform 可以有效地压缩字符串。并且可以bzgrep在压缩数据中搜索子串。
另一种方法是按高度和子节点数对树中的子树进行排序。
bool compare(TNode*other) {
if(height != other->height)
return height < other->height;
return nchildren < other->nchildren;
}
请注意,会有 O(n^2) 个子树。为了减少数量,我们可以使用基于高度的一些范围。例如,我们只能对高度为 1000 到 1500 的子树感兴趣。
生成排序后的数据时,可以在其中进行二进制搜索,并在 O(lg n) 时间内查找它是否是子集(考虑到排序后的数据中没有重复)。