C 查找第一棵树是否是第二棵树的子集

C 查找第一棵树是否是第二棵树的子集,c,tree,binary-tree,subtree,C,Tree,Binary Tree,Subtree,我查遍了互联网,想知道如何检查一棵树是否是另一棵树的子集。所谓子集,我的意思是,如果第一棵树的所有元素都出现在第二棵树中,那么issubset函数应该返回1 否则为0。请注意,根据元素的插入顺序,具有相同元素集的两棵树可以具有非常不同的形状。以树的形式给出以下示例: Elements of the first tree 4 / \ 2 6 / \ / \ 1 2 5 7 E

我查遍了互联网,想知道如何检查一棵树是否是另一棵树的子集。所谓子集,我的意思是,如果第一棵树的所有元素都出现在第二棵树中,那么
issubset
函数应该
返回1
否则为
0
。请注意,根据元素的插入顺序,具有相同元素集的两棵树可以具有非常不同的形状。以树的形式给出以下示例:

Elements of the first tree
             4
           /  \
         2     6
        / \   / \
       1   2  5  7 


Elements of the second Tree
            6
          /   \
         4     7
        /  \
       2    5
      / \
     1   2    
以下代码遍历树,然后检查值:

int issubset(nodeT **tree1, nodeT **tree2) {

    if( *tree2 == NULL)
        return TRUE;
    if(*tree1 == NULL)
        return FALSE;

    if(are_identical(&(*tree1),&(*tree2)))
        return TRUE;

    return issubset(&(*tree1)->pLeft, &(*tree2)) || issubset(&(*tree2)->pRight, &(*tree2));
}

int are_identical(nodeT **tree1, nodeT **tree2) {
    nodeT **temp;
    int iFound = 0, i, r;   
    if( *tree2 == NULL)
        return TRUE;

    if( (*tree1) ==NULL && (*tree2) ==NULL) {
        return FALSE;
    }

    if( (*tree1)->iValue != (*tree2)->iValue) {
        if(iFound = 0)
            return TRUE;

        i = issubset(&(*tree1)->pLeft, &(*tree2));
        if( i ==0) {
            r = issubset(&(*tree1)->pRight, &(*tree2));
            return r;
        }

        return i;
    }   

    return((*tree1)->iValue == (*tree2)->iValue && are_identical(&(*tree1)->pLeft, &(*tree2)->pLeft) && 
           are_identical(&(*tree1)->pRight, &(*tree2)->pRight) );
}

使用给定的示例运行代码后,我的输出返回第一棵树不是第二棵树的子集,而实际上它是一个子集

二进制搜索树支持对元素进行有效的排序迭代。在每个树的元素上以非减量顺序维护一个迭代器。重复以下步骤,直到确定结果:

  • 如果第一个迭代器没有更多元素,则返回
    TRUE
  • 如果第二个迭代器没有更多的元素,则返回
    FALSE
  • 如果第一个迭代器的当前元素小于第二个迭代器的当前元素,则返回
    FALSE
  • 如果第一个迭代器的当前元素等于第二个迭代器的当前元素,则更新两个迭代器
  • 如果第一棵树的当前元素大于第二棵树的当前元素,则更新第二个迭代器。(您可以通过跳过某些元素来优化此设置。)

基本实现是最坏情况
O(n+m)
,其中
n
m
分别是两棵树的大小。通过上面提到的优化,如果较大的树是平衡的,那么您可以通过
O(n log m)
另外绑定它,如果第二棵树比第一棵树大得多,这是有用的。(无论树是否平衡,
O(n+m)
界限仍然适用。)

我不确定我是否理解你的问题,但我仍然试图给你我的答案。从您的示例中,我假设您使用的是二进制搜索树。但是我不知道你用的是什么样的二叉树,我会假设一个通用的方案。我想如果这棵树是平衡的,也许你可以得到一个更好的算法

由于您有二进制搜索树,因此可以假设函数
search(root,key)
,如果找到了包含
key
的节点,该函数将返回有效指针,否则返回
NULL
的节点

另外,我假设您知道每个树的节点数。因此,如果
tree1
的节点数小于
tree
,则可以返回
0
。否则,方法如下:

int tree1_contained_in_tree2(node * tree1, node * tree2)
{
  if (tree1 == NULL) // am I visiting a empty tree?
    return 1;

  // so I am sure tree1 is not NULL ==> I search the contained key in tree2
  if (search(tree2, tree1->key) == NULL)
    return 0; // tree1->key does not belong to tree2

  // here tree1->key belongs to tree1 so, I test with the subtrees of root
  return tree1_contained_in_tree2(tree1->left, tree2) && 
         tree1_contained_in_tree2(tree1->right, tree2);    
}
我更喜欢使用指向节点的简单指针,而不是双指针。我想你可以让我的方法适应你的


如果
tree2
是平衡的(
O(nm)
),则算法为
O(nlogm)
,其中
n
tree1
的节点数,
m
tree2

的节点数,第一棵树不是第二棵树的子树,因为它具有不同的拓扑结构。你的意思是检查第一棵树的元素是第二棵树元素的子集吗?@augura我已经修改了这些树picture@EduardoJuarez还是错了。4和5在第二棵树中相邻,但不是第一棵树。你是对的。我编辑了我的标签,我编辑了我的问题@augurar@irleon您的实现是正确的!我完全忘了搜索。事实上,使用双精度点是乏味的,但我认为双精度点很有趣。如果
tree2
不平衡,那么这可能是最坏的情况
O(nm)
。如果树允许,您可能需要稍微修改它以考虑重复元素。虽然这个答案对于二进制搜索树(BST)是正确的,他的树不是BST,因为它们不包含不同的成员-两个2。@JonnyHenly此算法适用于支持排序迭代的任何数据结构。这将检查较大集合中每个元素的副本是否至少与较小集合相同。