一、如何判断两棵树是否同构
两棵树同构:对于两棵树,比较相对应的结点,如果该结点下的左右子树完全相同,且考虑左右互换,对于每个结点都是如此
下面是浙大何老师课上的PPT:
二叉树表示:
和一般的二叉树不同,这里为了方便比较二叉树的不同,采用了静态链表存储,即物理存储结构是数组,但具有链表的灵活性,通过数组下标链接下一个结点
struct TreeNode
{
ElementType Element;
Tree Left;
Tree Right;
}T1[MaxTree],T2[MaxTree];
二、代码实现:
#include<iostream>
using namespace std;
#define MaxTree 10
#define ElementType char
#define Tree int
#define Null -1 //std中的NULL默认为0,而0为数组的第一个下标
struct TreeNode
{
ElementType Element;
Tree Left;
Tree Right;
}T1[MaxTree],T2[MaxTree];
Tree BuildTree(struct TreeNode T[])
{
ElementType cl,cr;
Tree N,Root,check[10],i;//Root是结构数组的下标,也是根节点的下标
cin >> N;//输入树的元素个数
if(N)
{
for(i=0;i<N;i++) check[i] = 0;//check数组用来记录哪一个结点没有被其他结点指过,说明该结点是根节点,初始化为0,表示全未被指过
for(i=0;i<N;i++)//遍历N次,从数组下标开始
{
cin >>T[i].Element;//cl,cl是char型的左右值,还要转换成整型
cin >> cl;
cin >> cr;
if(cl!='-')//输入‘-’说明其左子节点非空
{
T[i].Left = cl-'0';//类型转换成整型
check[T[i].Left] = 1;//说明这个结点被指过,不能是根结点
}
else T[i].Left = Null;//子节点为空,其左右值设为-1
if(cr!='-')//输入‘-’说明其左子节点非空
{
T[i].Right = cr-'0';//类型转换成整型
check[T[i].Right] = 1;//说明这个结点被指过,不能是根结点
}
else T[i].Right = Null;
}
for(i=0;i<N;i++)
if(!check[i]) break;//遍历,直到直到找到根节点
Root = i;
}
return Root;
}
int Isomorphic(Tree R1,Tree R2)
{
//第一个树且第二个树都为空,返回相同
if((R1==Null)&&(R2==Null)) return 1;
//第一个结点空,第二个非空或者反之,返回不同
if(((R1==Null)&&(R2!=Null)) || ((R1!=Null)&&(R2==Null)))
return 0;
//结点元素不相同
if(T1[R1].Element!=T2[R2].Element) return 0;
//左子树均为空,则继续判断右子树
if((T1[R1].Left==Null)&&T2[R2].Left==Null)
return Isomorphic(T1[R1].Right,T2[R2].Right);
//左子树均非空,且元素相同,则需继续判断其根节点的左右子树,这里为什么不对其右子树直接判断?是因为return语句进行递归的过程中会对其右子树进行判断,在此判断多此一举
if(((T1[R1].Left!=Null)&&(T2[R2].Left!=Null))&&
((T1[T1[R1].Left].Element==T2[T2[R2].Left].Element)))
return (Isomorphic(T1[R1].Left,T2[R2].Left)&&//判断其左子树
Isomorphic(T2[R1].Right,T2[R2].Right));//判断其右子树
else//否则则可能是对称同构,需要进一步判断是否左=右,和右=左
return (Isomorphic(T1[R1].Left,T2[R2].Right)&&
Isomorphic(T1[R1].Left,T2[R2].Left));
}
int main()
{
Tree R1,R2;
R1 = BuildTree(T1);//建立第一棵结构数组二叉树
R2 = BuildTree(T2);//第二棵
cout << R1<<endl;
cout << R2<<endl;
if(Isomorphic(R1,R2)) cout << "Yes"<<endl;//判断是否同构
else cout<<"No"<<endl;
return 0;
}
这里我进行两次比较:
第一次:是图二的上下两个数组,对应的二叉树也画在了右边,这两棵树明显同构,再来看看代码跑出来的结果:
没错!
再来看看图二的下面两棵树:明显对于A结点,即使交换左右子树,也不是同一颗二叉树,对于B结点,是对称同构的,所以整个一棵树并非是同构的,看代码结果:
Bingo!