数据结构之树的同构

目录

前言

题意理解

求解思路

二叉树表示

 程序框架搭建

读数据建二叉树

二叉树同构判别


前言

本篇主要讲有关二叉树的同构判断。

题意理解

给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2,则称这两棵树是“同构”的。

例如:

 

左图通过若干次左右孩子的交换变成了右图。这两颗树是同构的。

 这两棵树不同构。左图树中C有一个孩子G,右图树中C有两个孩子D,E。

题目:输入两棵二叉树的信息,判断是否同构。

输入格式:输入给出两棵二叉树的信息:

  • 先在一行中给出该树的结点数,随后N行
  • 第i行对应编号第i个结点,给出该结点中存储的字母、其左孩子结点的编号、右孩子结点的编号。
  • 如果孩子结点为空,则在相应位置上给出“-”。

例:

###输入样例:

8
0A12
1B34
2C5-
3D--
4E6-
5G7-
6F--
7H--

第一个整数8,表示此二叉树有8个结点。

每个结点的信息主要有三个数据,黑色字体的第一列代表了这个结点本身的信息,这里用A,B,C……代表了每个结点的信息;后面的两个整数分别代表了左右儿子对应的编号。

红色字体的一列是对每个结点的编号。比如A的左儿子是B,对应B的编号为1;A的右儿子是C,对应C的编号为2。

再例如:

 ###输入样例:

8
0G-4
1B76
2F--
3A51
4H--
5C0-
6D--
7E2-

注意:在这样的输入表示方法里面,不要求根结点作为第一个数据输入,可按任意的顺序来输入每个结点的信息。

但是有很关键的一点:根结点在哪里?

没有哪个结点会指向根结点,根结点所对应的编号不会被输入,则没有被输入的编号对应根结点。

求解思路

要想解决这道题有三个问题:

  1. 二叉树的表示
  2. 构建二叉树
  3. 同构判别

二叉树表示

二叉树表示二叉树的表示方法最常见的是用链表,但也可以用数组来表示。

 数组表示二叉树最典型的形式就是将二叉树看作一个完全二叉树,缺少的结点在数组里面空出来。

这里用结构数组表示二叉树:静态链表

即基本的存储用数组,把需要的结点信息存储在数组里面,但是左右儿子用类似链表的方法来表示,有一个数据来指示左儿子在哪里、右儿子在哪里。物理上的存储是用数组,但是采用了链表的思想。

例:

ABCD
Left-12-1-1
Right13-1-1
01234

数组里的每个分量是一个结构,即每一列是数组的一个分量。这个结构包含三个信息,一个是结点本身的信息,另外Left与Right是指向左儿子与右儿子位置的下标。-1表示指向空的结点。

根据这样的表示方法可以定义相应的数据结构。

#define MaxTree 10
#define ElementType char
#define Tree int
#define Null -1

struct TreeNode
{
    ElementType Element;
    Tree Left;
    Tree Right;
}T1[MaxTree],T2[MaxTree];

注意:Left与Right不是指针,所以当它指向空缺的时候,不是用NULL(0),而是用Null(-1)。因为0是数组的下标,为了区分传统空指针的NULL,这里定义了一个 Null 。

二叉树用结构数组进行的表示不是唯一的。也可这样表示:

CDBA
Left-1-10-1
Right-1-113
01234

 程序框架搭建

int main()

{

        建二叉树1

        建二叉树2

        判别是否同构并输出

        return 0;

}

需要设计函数:

读数据建二叉树

二叉树同构判别

int main()
{
	Tree R1,R2;
	
	R1=BuildTree(T1);
	R2=BuildTree(T2);
	if(Isomorphic(R1,R2))  //判别两棵树是否同构
	    printf("Yes\n");
	else printf("No\n");
	
	return 0;
}

读数据建二叉树

Tree BuildTree(struct TreeNode T[])
{
	……
	scanf("%d\n",&N); //读入结点信息N个
	if(N){
		for(i=0;i<N;i++) check[i]=0;  //数组check对应N个结点
		for(i=0;i<N;i++){
			scanf("%c %c %c\n",&T[i].Element,&cl,&cr);//依次读入每个结点信息
			if(cl!='-'){   //若左儿子不为空
				T[i].Left = cl-'0'; //将字符转换为数字
				check[T[i].Left] = 1; //Left指向的结点的check值设为1
			}else T[i].Left = Null;
			if(cr!='-'){   //若右儿子不为空
				T[i].Right = cr-'0';
				check[T[i].Right] = 1; //Right指向的结点的check值设为1
			}else T[i].Right = Null; 
		}
		for(i=0;i<N;i++)  
			if(!check[i]) break;  //根结点check值为0
		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);
	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(T1[R1].Right,T2[R2].Right));
	else  /*两个左子树的元素不相同,判断1树的左子树是否与2树的右子树相同,1树的右子树是否与2树的左子树相同 */
		return (Isomorphic(T1[R1].Left,T2[R2].Right) && Isomorphic(T1[R1].Right,T2[R2].Left));
}

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值