PTA练习题: 树的同构

在网上做了一道简单的练习题,判断两棵树是否同构:

https://pintia.cn/problem-sets/1010070491934568448/problems/1040435498128044032

题目描述:给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A、B、G的左右孩子互换后,就得到另外一棵树。而图2就不是同构的。

输入格式:

输入给出2棵二叉树树的信息。对于每棵树,首先在一行中给出一个非负整数N (≤10),即该树的结点数(此时假设结点从0到N−1编号);随后N行,第i行对应编号第i个结点,给出该结点中存储的1个英文大写字母、其左孩子结点的编号、右孩子结点的编号。如果孩子结点为空,则在相应位置上给出“-”。给出的数据间用一个空格分隔。注意:题目保证每个结点中存储的字母是不同的。

输出格式:

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

输入样例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 -

输出:Yes 

输入样例2:

扫描二维码关注公众号,回复: 5590154 查看本文章

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

输出:No

题目分析及思路:

1.由于各个节点在输入时,顺序是不定的,因此它出现的顺序和它在树中的实际位置没有必然的联系。因此,我们首先肯定要用一个数组存储输入信息。

2.输入结束后,可以找到根节点:一棵树里面,有且仅有一个节点没有父节点,即根节点。由这个性质可以查找出根节点。

3.实际上,读入输入时,我们用来存储输入的数组就是一颗顺序存储的树了,因此没有必要再去用指针构造一棵树,以避免空间的浪费。在用指针给出一棵树时,我们只用给出这棵树的根结点的指针即可。这里同样,我们给出一棵树,除了数组(用来存储各节点信息及其左右child的位置)之外,还要给出这颗树的根节点在数组中的下标。这两个信息给出了一棵完整的树。

4.判断两棵树是否同构,可以利用递归的思想(这种思想在树中往往非常有用)。我们现在有两颗树了,判断它们是否同构,可以这么做:

(1)如果都是空树,同构。

(2)如果一棵空,一棵非空,不同构。

(3)如果两棵都非空,进一步判断:

(3.1)如果两棵树根节点的信息不相同,不同构。否则,还要进一步判断:

(3.1.1)如果树1左子树和树2左子树同构,那么就看树1和树2的右子树是否同构,如果是则树1树2同构,否则不同构。

(3.1.2)如果树1左子树和树2右子树同构,那么就看树1右子树和树2左子树是否同构,如果是则树1树2同构,否则不同构。

(3.1.3)如果树1的左子树和树2的左、右子树都不同构,则树1树2不同构。

显然,这些操作可以利用递归实现。

代码实现(C):

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

struct treeElement {    //树中每个节点储存的信息如下:
	char key;
	int leftIndex;
	int rightIndex;
};

struct treeInformation {    //一棵树,由存储节点信息的数组+根节点的下标组成
	struct treeElement * treeArray;
	int root;
};

typedef struct treeInformation * binaryTree;

int isEmptyTree(binaryTree t)//判断是否空树
{
	return t->root==-1;
}

int findRootIndex(int number, struct treeElement * input) {  //在输入后,寻找到整棵树的根节点
	int i, root = -1;
	int * tag = (int *)malloc(sizeof(int)*number);
	for (i = 0; i < number; i++)tag[i] = 0;
	for (i = 0; i < number; i++) {
		if (input[i].leftIndex != -1)tag[input[i].leftIndex] = 1;
		if (input[i].rightIndex != -1)tag[input[i].rightIndex] = 1;
	}
	for (i = 0; i < number; i++) {
		if (tag[i] == 0) {
			root = i;
			break;
		}
	}
	free(tag);
	return root;
}

binaryTree createInputTree()// 接受输入,并找到根节点,构造出整棵树
{
	int number, i;
	char number1[10], number2[10];
	scanf("%d", &number);
	struct treeElement * input = (struct treeElement *)malloc(sizeof(struct treeElement)*number);
	for (i = 0; i < number; i++) {
		scanf("\n%c %s %s", &input[i].key, &number1, &number2);
		if (number1[0] != '-')input[i].leftIndex = atoi(number1);
		else input[i].leftIndex = -1;
		if (number2[0] != '-')input[i].rightIndex = atoi(number2);
		else input[i].rightIndex = -1;
	}
	if (number <= 0) {
		binaryTree t = (binaryTree)malloc(sizeof(struct treeInformation));
		t->root = -1; t->treeArray = NULL;
		return t;
	};
	int root = findRootIndex(number, input);
	if (root < 0) {
		printf("ERROR!\n");
		return NULL;
	}
	binaryTree t = (binaryTree)malloc(sizeof(struct treeInformation));
	t->root = root; t->treeArray = input;
	return t;
}

int isIsostructural(binaryTree t1, binaryTree t2)//判断两棵树是否同构
{
	if (isEmptyTree(t1) && isEmptyTree(t2))return 1;
	if ((!isEmptyTree(t1) && isEmptyTree(t2)) || (isEmptyTree(t1) && !isEmptyTree(t2)))return 0;
	else {
		if (t1->treeArray[t1->root].key != t2->treeArray[t2->root].key)return 0;
		binaryTree leftChild1 = (binaryTree)malloc(sizeof(struct treeInformation));
		binaryTree leftChild2 = (binaryTree)malloc(sizeof(struct treeInformation));
		binaryTree rightChild1 = (binaryTree)malloc(sizeof(struct treeInformation));
		binaryTree rightChild2 = (binaryTree)malloc(sizeof(struct treeInformation));
		
		leftChild1->treeArray = t1->treeArray; rightChild1->treeArray = t1->treeArray;
		leftChild1->root = t1->treeArray[t1->root].leftIndex; rightChild1->root = t1->treeArray[t1->root].rightIndex;
		leftChild2->treeArray = t2->treeArray; rightChild2->treeArray = t2->treeArray;
		leftChild2->root = t2->treeArray[t2->root].leftIndex; rightChild2->root = t2->treeArray[t2->root].rightIndex;

		if (isIsostructural(leftChild1, leftChild2)) {
			if (isIsostructural(rightChild1, rightChild2)) {
				free(leftChild1); free(leftChild2); free(rightChild1); free(rightChild2);
				return 1;
			}
		}
		if (isIsostructural(leftChild1, rightChild2)) {
			if (isIsostructural(rightChild1, leftChild2)) {
				free(leftChild1); free(leftChild2); free(rightChild1); free(rightChild2);
				return 1;
			}
		}
		free(leftChild1); free(leftChild2); free(rightChild1); free(rightChild2);
		return 0;
	}
}

int main()//主函数
{
	binaryTree t1 = createInputTree();
	binaryTree t2 = createInputTree();
	if (isIsostructural(t1, t2))printf("Yes");
	else printf("No");
	system("pause");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Europe233/article/details/83046486