Один из простых способов - написать метод 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 << ')';
}
И мы можем использовать некоторый оптимизированный алгоритм, например, Алгоритм Кнута-Морриса-Пратта , чтобы найти (возможно, за O (n) время) существование подстроки и, в конце концов, найти дерево это поддерево другого.
И снова строка может быть эффективно сжата с помощью 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) (учитывая, что в отсортированных данных нет дубликатов).