【编程题】7-3树的同构
- 软件开发
- 2025-09-12 10:33:02

7-3 树的同构 1 题目原文2 思路解析3 代码实现4 总结 1 题目原文
题目链接:7-3 树的同构
给定两棵树 T 1 T_1 T1 和 T 2 T_2 T2。如果 T 1 T_1 T1 可以通过若干次左右孩子互换就变成 T 2 T_2 T2,则我们称两棵树是“同构”的。例如图 1 1 1 给出的两棵树就是同构的,因为我们把其中一棵树的结点 A 、 B 、 G A、B、G A、B、G 的左右孩子互换后,就得到另外一棵树。而图 2 2 2 就不是同构的。
图1 图2
现给定两棵树,请你判断它们是否是同构的。
输入格式:
输入给出 2 2 2 棵二叉树的信息。对于每棵树,首先在一行中给出一个非负整数 n ( ≤ 10 ) n (≤10) n(≤10),即该树的结点数(此时假设结点从 0 0 0 到 n − 1 n−1 n−1 编号);随后 n n n 行,第 i i i 行对应编号第 i i i 个结点,给出该结点中存储的 1 1 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 2 思路解析本题考查二叉树的相关知识。由题意可以了解到,二叉树的每个结点不是必须交换左右子树。判断二叉树是否同构在本质上是判断两棵二叉树是不是“相同”的,只是这个“相同”不是左子树和左子树“相同”,右子树和右子树“相同”,而是左子树可能和左子树“相同”,也可能和右子树“相同”,右子树同理。 将上面的“相同”替换成“同构”,于是递归思路便呼之欲出,具体如下: 1. 判断二叉树 A 和二叉树 B 是否同构; 2. 若 A 是空树且 B 是空树,则同构; 3. 若一棵树是空树但另一棵树不是空树,则不同构; 4. 若两棵树都不是空树,则同构需满足: 4.1 当前结点的值相同; 4.2 当前 A 结点的左子树和 B 的右子树相同且当前 A 结点的右子树和 B 的左子树相同或当前 A 结点的左子树和 B 的左子树相同且当前 A 结点的右子树和 B 的右子树相同。 递归体现在 4.2 中。 这道题的迭代思路和递归思路类似,甚至有点相当于将递归硬改成迭代了,意义不大,故不做记录。
3 代码实现需要注意的是,此题中给出的树是采用的“孩子表示法”表示的,但存储方式是顺序存储的,与一般的“二叉链表表示法”(链式存储)有所不同,这里将其“统一化”为二叉链表表示法,然后进行处理。
#include <stdio.h> #include <stdlib.h> // 二叉树结点定义 typedef struct TNode { char val; struct TNode *lc, *rc; } TNode, Tree; // 根据孩子表示法的数组构建二叉链表树 Tree *create_tree(char tree_arr[][3], int n, char null) { TNode *tn_arr[n]; int i = 0, p[n]; // 第一遍先创建所有结点并初始化“是否有父结点”的标志数组 for (i = 0; i < n; i++) { tn_arr[i] = (TNode *)malloc(sizeof(TNode)); tn_arr[i]->val = tree_arr[i][0]; tn_arr[i]->lc = tn_arr[i]->rc = NULL; p[i] = 0; } // 第二遍将这些结点组合成树 for (i = 0; i < n; i++) { if (tree_arr[i][1] != null) { tn_arr[i]->lc = tn_arr[tree_arr[i][1] - '0']; p[tree_arr[i][1] - '0'] = 1; } if (tree_arr[i][2] != null) { tn_arr[i]->rc = tn_arr[tree_arr[i][2] - '0']; p[tree_arr[i][2] - '0'] = 1; } } // 第三遍找出根结点并返回这棵树 for (i = 0; i < n; i++) { if (!p[i]) return tn_arr[i]; } return NULL; } // 判断两棵链式二叉树是否同构 int is_isomo(Tree *r1, Tree *r2) { // 两个都是空树,同构 if (!r1 && !r2) return 1; // 一个是空树一个不是,不同构 if (!r1 || !r2) return 0; // 两个都不是空树 return r1->val == r2->val && (is_isomo(r1->lc, r2->lc) && is_isomo(r1->rc, r2->rc) || is_isomo(r1->lc, r2->rc) && is_isomo(r1->rc, r2->lc)); } // 销毁二叉树 void destroy_tree(Tree *root) { if (!root) return; destroy_tree(root->lc); destroy_tree(root->rc); free(root); } int main(void) { // 读入数据 int n = 0, m = 0, i = 0; scanf("%d", &n); char tree_a[n][3]; for (i = 0; i < n; i++) { scanf(" %c %c %c", &tree_a[i][0], &tree_a[i][1], &tree_a[i][2]); } scanf("%d", &m); if (n ^ m) { printf("No\n"); return 0; } char tree_b[m][3]; for (i = 0; i < m; i++) { scanf(" %c %c %c", &tree_b[i][0], &tree_b[i][1], &tree_b[i][2]); } // 建树 Tree *aa = create_tree(tree_a, n, '-'); Tree *bb = create_tree(tree_b, m, '-'); // 判断是否同构 printf("%s\n", is_isomo(aa, bb) ? "Yes" : "No"); // 销毁 destroy_tree(aa); destroy_tree(bb); return 0; } 4 总结判断二叉树的同构,其解决方法与判断二叉树是否相同类似,并且天然地可以使用递归的解法解决。关于树与二叉树的问题,如果可以用迭代解决的优先选择迭代,不过有时候迭代的思路并不好想,或者迭代的思路很复杂,那么使用递归解决就好。
【编程题】7-3树的同构由讯客互联软件开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“【编程题】7-3树的同构”
上一篇
如何配置虚拟机IP?
下一篇
spark常见操作命令