很简单,假如说判断B是否为A的一个子树,则首先对A进行遍历,然后如果遍历时候节点的值等于B的根节点,则进入判断函数进行判断,如果完全一样,则该函数返回true,否则返回false,在后面递归判断时候,要判断前面函数返回的是true还是false,如果是true,则它的子树就不用再判断了,直接返回那个bool值,如果是false,则要对后面的左右子树依旧进行判断。
接下来讨论那个比较两棵树的函数,我们可以看到,如果假设B是A的子集,且设置两个指针,分别指向其两个树的根节点,二者同时开始进行遍历,可以看到有以下几种情况
A B 代号 bool值
有 空 甲 true
有 有 乙 看值是否相等来判断
空 空 丙 true
空 有 丁 false
空,就是遍历时候,当前节点为空,有意思就是,相反,当前节点不为空
上面这四种情况的目的在于如何让程序判断递归截止
对于乙情况,不用考虑,我们只考虑边界情况
甲丙丁三种情况,可以看到,在B为空时候,boo值为true,也就是说,B为A的
#include <iostream>
using namespace std;
typedef struct _BiTree
{
int data;
struct _BiTree *left;
struct _BiTree *right;
}BiTree,* PBiTree;
PBiTree BuildTree()
{
int data;
cin>>data;
if(data==-1)
return NULL;
PBiTree p=(PBiTree )malloc(sizeof(BiTree));
p->data=data;
p->left=BuildTree();
p->right=BuildTree();
return p;
}
void Print(PBiTree p)
{
if(p==NULL)
return;
cout<<p->data;
Print(p->left);
Print(p->right);
}
bool SameTree(PBiTree p1,PBiTree p2)
{
if(p2==NULL)
return true;
if(p1==NULL)
return false;
if(p1->data!=p2->data)
return false;
return SameTree(p1->left,p2->left)&&SameTree(p1->right,p2->right);
}
bool JudgeTree(PBiTree p1,PBiTree p2)
{
bool ret;
if(p1==NULL||p2==NULL)
return false;
if(p1->data==p2->data)
ret=SameTree(p1,p2);
if(!ret)
JudgeTree(p1->left,p2);
if(!ret)
JudgeTree(p1->right,p2);
return ret;
}
int main()
{
PBiTree p1;
PBiTree p2;
p1=BuildTree();
Print(p1);
p2=BuildTree();
Print(p2);
if(JudgeTree)
cout<<"2 is 1's subtree"<<endl;
else
cout<<"2 is 1's not subtree"<<endl;
return 0;
}
子树
而A为空且B为有的时候,才为false
if(A==NULL&&B!=NULL)
return false
if(B==NULL)
return true;
可以发现,上述代码可以优化为
if(B==NULL)
return true;
if(A==NULL)
return false
代码如下