欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

树的同构

程序员文章站 2022-06-07 21:46:38
...

最近为了准备PAT考试,重新复习了数据结构,把数据结构的题发上来,以便于自己日后复习

树的同构树的同构树的同构

和树有关的操作一般都可以通过递归来很清晰地实现,递归中注意跳出递归的条件(就是两个节点为空的情况)

1.当甲与乙中至少有一个空树的时候,则甲与乙必须同时为空树,否则就不可能为同构

2.甲与乙不为空时,但是数据不同也不同构

3.最重要的就是要判断甲的左跟乙的右&&甲的右与乙左是否相等,相等说明左右子树有交换为同构,或者是甲的左跟乙的左

&&甲的右跟乙的右是否相等,若相等则说明甲与乙的儿子节点位置完全相同,为同构

#include<stdio.h>
#pragma warning(disable:4996)
#define MaxTree 10
#define Null -1     //将Null定义为-1而不能是0,因为数组下标为0的地方仍保存有节点
typedef char ElementType;
typedef int Tree;
struct TreeNode {    //定义二叉树节点
	ElementType Data;
	Tree Left;
	Tree Right;
}T1[MaxTree], T2[MaxTree];
int N, check[MaxTree];   //check数组用于寻找树的根节点

Tree BuildTree(struct TreeNode T[]) {
	int Root = Null, i;    //刚开始将节点置为空,若为空树的时候可返回Null
	char cl, cr;
	scanf("%d", &N);
	if (N) {              //如果不为空树的话
		for (i = 0; i<N; i++) check[i] = 0;    //将check数组置为0
		for (i = 0; i<N; i++) {
			scanf("\n%c %c %c", &T[i].Data, &cl, &cr); //把换行符放在前面吃掉前面scanf后的回车,而最后一个scanf不能有回车,一举两得
			if (cl != '-') {
				T[i].Left = cl - '0';
				check[T[i].Left] = 1;//将左节点标记,最终没有被标记的就是根结点
			}
			else
				T[i].Left = Null;

			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;//没有被check的节点为头结点
		Root = i;
	}
	return Root;
}
int Isomorphic(Tree R1, Tree R2) {
	if ((R1 == Null)||(R2 == Null))      //如果为空树则是同构的
		return R1==R2;
	if ((T1[R1].Data) != (T2[R2].Data))//如果数据不同则不是同构的
		return 0;
	return( Isomorphic(T1[R1].Left, T2[R2].Left) && Isomorphic(T1[R1].Right, T2[R2].Right))||( Isomorphic(T1[R1].Left, T2[R2].Right) && Isomorphic(T1[R1].Right, T2[R2].Left));
	//判断左子树的左儿子与右子树的右儿子,左子树的右儿子与右子树的左儿子是否相同----这种情况是两个子树的儿子节点有交换
	//判断左子树的左儿子与右子树的左儿子,左子树的右儿子与右子树的右儿子是否相同----这种情况是两个子树的儿子节点没有交换
}
int main() {
	Tree R1, R2;     //首先建立两棵树,R1,R2为树的根节点
	R1 = BuildTree(T1);
	R2 = BuildTree(T2);
	if (Isomorphic(R1, R2))   //Isomorphic函数判断是否同构
		printf("Yes\n");
	else printf("No\n");
	return 0;
}