所以,我有一个明显的暴力算法,如下所示
int isSubtree (binTree *S, binTree *T)
{
if (S == NULL)
return 0;
return (isEqual (S,T) || isSubtree (S->left, T) || isSubtree (S->right, T));
}
int isEqual (binTree *S, bintree *T)
{
if (S==NULL && T==NULL)
return 1;
if (S==NULL || T==NULL)
return 0;
if (S->val == T->val)
return isEqual(S->left,T->left) && isEqual (S->right,T->right);
else
return 0;
}
但这是O(n²)方法。
我有另一种方法如下,是O(n) 我们以顺序方式遍历第一棵树并将其存储在一个数组中。然后我们遍历第二棵树并按顺序存储它。现在,如果第二个数组是第一个数组的子数组,我们继续前进并重复相同的procodure for preorder遍历。如果两个查询都为TRUE,则树是第一个树的子树。否则,不是。
有人可以告诉我以下算法是否可行?
是否有针对此问题的空间优化解决方案?
注意:我需要两个数组,因为我存储了两个数组的遍历,无论如何我只能用一个数组做?就像我将存储其中一个树的inorder遍历,然后使用该数组在遍历另一个树时检查子数组条件。 或者也许没有额外的空间,但O(n)时间复杂度?
注意:通过子数组,我的意思是元素应该连续出现,即
{2,3,5} is a subarray of {1,2,3,5} but not a subarray of {1,2,3,4,5}
答案 0 :(得分:1)
摘要:考虑在每个节点中存储散列和/或子树大小以加速搜索。您提出的算法已被破坏。
如果我已正确理解您提出的替代算法,那么它就不起作用。作为反例,请考虑:
T S
x x
/ \ / \
y z y z
\
q
T遍历yxz,预先订购xyz。 S有序遍历yxzq,预先订购xyzq。
因此,尽管T不是有效匹配(根据你的递归方法),但是T的遍历被嵌入在S中。
我一直在考虑Karthikeyan的建议 - 在每个节点存储子树深度,因为它可以让你进行大量的比较。当然,如果动态维护它会使某些树操作更加昂贵 - 必须优先考虑那些或在子树查找期间额外命中。
存储子树元素的哈希是另一种可能性。有意义的取决于树的结构和数据与子树发现相比的动态变化,以及从整体性能角度来看是否更为重要。
无论如何,有很多关于此的问题,例如: Find whether a tree is a subtree of other。哦 - 发现了这个 - Determine if a binary tree is subtree of another binary tree using pre-order and in-order strings - 这似乎支持了我的逻辑,因为你说递归方法是正确的但是很慢。
答案 1 :(得分:0)
如何进行深度优先搜索并在每个节点上存储子树节点的数量,并仅比较父节点的子树,其节点数与所讨论的另一个树相同。
答案 2 :(得分:0)
我们可以使用inorder遍历和DFS(在二叉树中,它减少到预先遍历遍历)。现在首先使用DFS,修改两个树的数据结构,并在每个节点存储其下的子树。 之后,为两个树写入inorder遍历,然后将字符串与KMP匹配。在O(n + m)(两个树中的n& m-节点)中,我们可以找出不同的匹配。我们可以使用散列来连接到带有DFS的修改图。在每次与KMP匹配时,我们可以比较两者的DFS修改图(在子树的数量上),如果它与整个序列匹配,它是一个子树,否则我们去另一个KMP匹配,所以上。
在上面的例子中,DFS之后的修改数据结构'T'是[x(2); y(0); z(0)]&对于'S'[x(3); y(0); z(1); q(0)]。 为'T':yxz 为了'S':yxzq
我们得到了匹配'yxz'。现在我们转到DFS修改过的结构。 x处存在不匹配;所以,'T'不是'S'的子树。
答案 3 :(得分:0)
在数组{2,3,5}中,root可以是2,或3或5,因此您不能使用这样的数组来表示树。
如果A是B的子树(与您的代码类似),并假设leafs(x)
是从左到右的“树x叶子节点”的数组,则叶子(A)是叶子的子串(B)。
一旦找到上面的子字符串,检查从leaf到root的节点,确保它确实是一个子树。