第六章树和二叉树--树和森林-计算机17级 7-1 树的同构 (25 分)

7-1 树的同构 (25 分)

给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A、B、G的左右孩子互换后,就得到另外一棵树。而图2就不是同构的。
在这里插入图片描述
现给定两棵树,请你判断它们是否是同构的。
输入格式:
输入给出2棵二叉树树的信息。对于每棵树,首先在一行中给出一个非负整数N (≤10),即该树的结点数(此时假设结点从0到N−1编号);随后N行,第i行对应编号第i个结点,给出该结点中存储的1个英文大写字母、其左孩子结点的编号、右孩子结点的编号。如果孩子结点为空,则在相应位置上给出“-”。给出的数据间用一个空格分隔。注意:题目保证每个结点中存储的字母是不同的。

输出格式:
如果两棵树是同构的,输出“Yes”,否则输出“No”。

输入样例1(对应图1):

8
A 1 2
B 3 4
C 5 -
D - -
E 6 -
G 7 -
F - -
H - -
8
G - 4
B 7 6
F - -
A 5 1
H - -
C 0 -
D - -
E 2 -
输出样例1:
Yes
输入样例2(对应图2)
8
B 5 7
F - -
A 0 3
C 6 -
H - -
D - -
G 4 -
E 1 -
8
D 6 -
B 5 -
E - -

H - -
C 0 2
G - 3
F - -
A 1 4

输出样例2:
No

题意理解:
  1. 先在一行输入一个N,下面有N行输入
  2. 每一行对应一个结点,给出该结点储存的数据,左孩子编号,右孩子编号,如果孩子结点为空,那么就输入一个“-”
程序大致框架:

1.构造二叉树的结构体
2.创建二叉树
3.进行同构判断

二叉树的结构体表示:

typedef struct{
	char data; //储存的数据
	int lchild;//左孩子结点的位置
	int rchild;//有孩子结点的位置
}TNode;

二叉树的创建:

这里给出的二叉树表现形式,适合使用顺序链表存储,即创建一个数组,数组的每个元素是一个结点类型的结构体,如果想要达到遍历二叉树的效果,只需要找出根结点在数组中的位置

int main()
{
	TNode Tree1[10];//创建二叉树Tree1,因为N最大为10,所以结点最多为10个
	TNode Tree2[10];//创建二叉树TREE2
	//创建完树以后,将N个结点顺序输入到树种,并找出根结点所在位置
	//CreatTree(TNode T[])函数,实现读取数据,并返回根节点位置的功能
	int root1 = CreatTree(Tree1);//int类型的root1变量,代表Tree1中根结点的位置
	int root2 = CreatTree(Tree2);//int类型的root2变量,代表Tree2中根结点的位置
	进行同构判断;
}

下面是CreatTree(TNode T[])函数的实现
在这部分代码中,使用了一个JudgeRoot[]数组进行判断树种的每个结点是不是根结点,原理很简单,就是将这个数组的长度设置为和树中结点数相同,在树数组中i位置的结点如果有孩子,那么就将JudgeRoot[]数组中该结点的孩子位置设为1,遍历JudgeRoot[]数组,零所在的下标即为树中根节点的下标

int CreatTree(TNode T[])
{
	int N;
	scanf("%d",&N);//输入一个N,接下来输入N行结点数据
	getchar()//读取回车
	char data,lc,rc;
	int Root = NULL;//将根节点变量初始化为NULL,如果不初始化,树空时返回Root会发生错误
	int JudgeRoot[N];
	for(int i=0;i<N;i++)
		JudgeRoot[i]=0;
	for(int i=0;i<N;i++)
	{
		scanf("%c %c %c",&data,&lc,&rc);//输入结点的三个数据,暂存于data,lc,rc中
										//lc,rc类型为char是因为,lc,rc可能是'-'
		getchar();//读取回车
		T[i].data=data//将data存储的数据赋值给结点中的data
		if(lc!='-')
		{
			T[i].lchild = lc-'0'; //因为一开始输入是以char类型输入的,所以要将其转化为int类型
			JudgeRoot[T[i].lchild]=1;//将该结点左孩子位置设为1,代表该位置存放的不是根节点
		}
		else
			T[i].lchild = NULL;//注意这里的left和right不是指针,而是游标。所以当他们都指向空的
			//时候,NULL可不是0,而是-1(c++规定空指针=0.而为了区分这里把NULL设为-1)
		//同理右孩子也是如此
		if(rc!='-')
		{
			T[i].rchild = rc-'0'; //因为一开始输入是以char类型输入的,所以要将其转化为int类型
			JudgeRoot[T[i].rchild]=1;//将该结点左孩子位置设为1,代表该位置存放的不是根节点
		}
		else
			T[i].rchild = NULL;
	}
	for(int i=0;i<N;i++)
	{
		if(!JudgeRoot[i])
		{
			Root=i;
			break;
		}
	}
	return Root;
}

同构的判断

判断同构的思想还是用递归的思想,即递归判断两棵树的左右子树是不是同构
判断同构需要考虑多种情况
1.都为空树;
2.一个为树为空,一个不为空
3.两个树都不为空
其中两个树都不为空还包括,左右子树是否为空,两个树的左右子树的同构判断需不需要换位

首先设置一个判断同构的函数,该函数返回值类型为布尔值类型,同构返回true,否则返回false,设这个函数名为bool Ifisomorphism(TNode Tree1[], int root1, TNode Tree2[], int root2)
下面为代码实现

bool Ifisomorphism(TNode Tree1[], int root1, TNode Tree2[], int root2)
{
	if(root1==NULL&&root2==NULL)
		return true;//如果两个树都为空, 返回true
	if((root1==NULL&&root2!=NULL)||(root1!=NULL&&root2==NULL))
		return false;//如果两个树,一个为空,一个不为空,返回false
	if(Tree1[root1].data!=Tree2[root2].data)
		return false;//如果两个树的根结点不相等,返回false
	else{//如果根节点相等
		if(Tree1[root1].lchild==NULL&&Tree22[root2].lchild==NULL)
		//如果两个树左子树都为空,那么比较两棵树的右子树
            return Ifisomorphism(Tree1,Tree1[root1].rchild,Tree2,Tree2[root2].rchild);
        else if(Tree1[root1].rchild==NULL&&Tree2[root2].rchild==NULL)
        //若果两棵树右子树都为空,那么比较两棵树的左子树
            return Ifisomorphism(Tree1,Tree1[root1].lchild,Tree2,Tree2[root2].lchild);
        else if(Tree1[root1].lchild==NULL&&Tree2[root2].rchild==NULL)
        //如果树一的左子树为空,树二的右子树为空,那么比较树一的右子树和树二的左子树
            return Ifisomorphism(Tree1,Tree1[root1].rchild,Tree2,Tree2[root2].lchild);
        else if(Tree[root1].rchild==NULL&&Tree2[root2].lchild==NULL)
        //如果树一的右子树为空,树二的左子树为空,那么比较树一的左子树和树二的右子树
            return Ifisomorphism(Tree1,Tree1[root1].lchild,Tree2,Tree2[root2].rchild);
        else{//若果两棵子树都不为空
            if(Tree1[Tree1[root1].lchild].data==Tree2[Tree2[root2].lchild].data)
            //两棵树的左子树根结点相等,那么不换位,直接左子树比较左子树,右子树比较右子树
                return Ifisomorphism(Tree1,Tree1[root1].lchild,Tree2,Tree2[root2].lchild)&&Ifisomorphism(Tree1,Tree1[root1].rchild,Tree2,Tree2[root2].rchild);
            else
            //如果不是,即两棵树的左子树根结点不相等,那么换位,左子树比较右子树,右子树比较左子树
                return Ifisomorphism(Tree1,Tree1[root1].lchild,Tree2,Tree2[root2].rchild)&&Ifisomorphism(Tree1,Tree1[root1].rchild,Tree2,Tree2[root2].lchild);
        }
	}
}

综上所述,本题的完整代码:

#include <bits/stdc++.h>
#define NULL -1

using namespace std;

typedef struct{
    char data;
    int lchild;
    int rchild;
} TNode;

int CreatTree(TNode T[]);
bool Ifisomorphism(TNode Tree1[], int root1, TNode Tree2[], int root2);

int main()
{
	TNode Tree1[10];//创建二叉树Tree1,因为N最大为10,所以结点最多为10个
	TNode Tree2[10];//创建二叉树TREE2
	//创建完树以后,将N个结点顺序输入到树种,并找出根结点所在位置
	//CreatTree(TNode T[])函数,实现读取数据,并返回根节点位置的功能
	int root1 = CreatTree(Tree1);//int类型的root1变量,代表Tree1中根结点的位置
	int root2 = CreatTree(Tree2);//int类型的root2变量,代表Tree2中根结点的位置
	//调用Ifisomorphism()进行同构判断;
	bool Judge = Ifisomorphism(Tree1[], root1, Tree2[], root2)if(Judge)
		printf("Yes");
	else
		printf("No");
	return 0;
}

int CreatTree(TNode T[])
{
	int N;
	scanf("%d",&N);//输入一个N,接下来输入N行结点数据
	getchar()//读取回车
	char data,lc,rc;
	int Root = NULL;//将根节点变量初始化为NULL,如果不初始化,树空时返回Root会发生错误
	int JudgeRoot[N];
	for(int i=0;i<N;i++)
		JudgeRoot[i]=0;
	for(int i=0;i<N;i++)
	{
		scanf("%c %c %c",&data,&lc,&rc);//输入结点的三个数据,暂存于data,lc,rc中
										//lc,rc类型为char是因为,lc,rc可能是'-'
		getchar();//读取回车
		T[i].data=data//将data存储的数据赋值给结点中的data
		if(lc!='-')
		{
			T[i].lchild = lc-'0'; //因为一开始输入是以char类型输入的,所以要将其转化为int类型
			JudgeRoot[T[i].lchild]=1;//将该结点左孩子位置设为1,代表该位置存放的不是根节点
		}
		else
			T[i].lchild = NULL;//注意这里的left和right不是指针,而是游标。所以当他们都指向空的
			//时候,NULL可不是0,而是-1(c++规定空指针=0.而为了区分这里把NULL设为-1)
		//同理右孩子也是如此
		if(rc!='-')
		{
			T[i].rchild = rc-'0'; //因为一开始输入是以char类型输入的,所以要将其转化为int类型
			JudgeRoot[T[i].rchild]=1;//将该结点左孩子位置设为1,代表该位置存放的不是根节点
		}
		else
			T[i].rchild = NULL;
	}
	for(int i=0;i<N;i++)
	{
		if(!JudgeRoot[i])
		{
			Root=i;
			break;
		}
	}
	return Root;
}

bool Ifisomorphism(TNode Tree1[], int root1, TNode Tree2[], int root2)
{
	if(root1==NULL&&root2==NULL)
		return true;//如果两个树都为空, 返回true
	if((root1==NULL&&root2!=NULL)||(root1!=NULL&&root2==NULL))
		return false;//如果两个树,一个为空,一个不为空,返回false
	if(Tree1[root1].data!=Tree2[root2].data)
		return false;//如果两个树的根结点不相等,返回false
	else{//如果根节点相等
		if(Tree1[root1].lchild==NULL&&Tree22[root2].lchild==NULL)
		//如果两个树左子树都为空,那么比较两棵树的右子树
            return Ifisomorphism(Tree1,Tree1[root1].rchild,Tree2,Tree2[root2].rchild);
        else if(Tree1[root1].rchild==NULL&&Tree2[root2].rchild==NULL)
        //若果两棵树右子树都为空,那么比较两棵树的左子树
            return Ifisomorphism(Tree1,Tree1[root1].lchild,Tree2,Tree2[root2].lchild);
        else if(Tree1[root1].lchild==NULL&&Tree2[root2].rchild==NULL)
        //如果树一的左子树为空,树二的右子树为空,那么比较树一的右子树和树二的左子树
            return Ifisomorphism(Tree1,Tree1[root1].rchild,Tree2,Tree2[root2].lchild);
        else if(Tree[root1].rchild==NULL&&Tree2[root2].lchild==NULL)
        //如果树一的右子树为空,树二的左子树为空,那么比较树一的左子树和树二的右子树
            return Ifisomorphism(Tree1,Tree1[root1].lchild,Tree2,Tree2[root2].rchild);
        else{//若果两棵子树都不为空
            if(Tree1[Tree1[root1].lchild].data==Tree2[Tree2[root2].lchild].data)
            //两棵树的左子树根结点相等,那么不换位,直接左子树比较左子树,右子树比较右子树
                return Ifisomorphism(Tree1,Tree1[root1].lchild,Tree2,Tree2[root2].lchild)&&Ifisomorphism(Tree1,Tree1[root1].rchild,Tree2,Tree2[root2].rchild);
            else
            //如果不是,即两棵树的左子树根结点不相等,那么换位,左子树比较右子树,右子树比较左子树
                return Ifisomorphism(Tree1,Tree1[root1].lchild,Tree2,Tree2[root2].rchild)&&Ifisomorphism(Tree1,Tree1[root1].rchild,Tree2,Tree2[root2].lchild);
        }
	}
}

总结:这篇代码也不是我自己想出来的,而是参考了好多优秀的代码,加上自己的理解得来的,加油吧!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值