【PTA】4-2 树的同构【数据结构】

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

bd291b3b99c44125838df959dc7f004f.png

图一 

7ccf1d7fa8394760ba22db7f714d90d9.png

图二 

现给定两棵树,请你判断它们是否是同构的。

输入格式:

输入给出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
  • 对于每棵树,其节点的数量、层次结构和连接关系必须完全一致。
  • 如果树上的节点带有特定的标签或值,则这些标签也必须一一对应相等。

 既然判断树的同构,那我们就应该先构建一个树形结构:

typedef struct tree
{
    char data;       // 节点数据
    int left;        // 左子节点索引
    int right;       // 右子节点索引
} tree;
  • 声明了两个全局数组T1T2,以及一个检查数组check,用于存储两棵树的节点信息和标记哪些节点已经被访问过。
// 全局数组用于存放两个树的节点信息
tree T1[MAXTREE], T2[MAXTREE];
// 检查数组,用于标记已访问过的节点
int check[MAXTREE];
  1. 构建树的函数 (buildTree()):

    • 接受一个指向tree结构体数组的指针参数t,用于接收用户输入并构建树。
    • 用户需要输入节点总数,然后依次输入每个节点的数据及其左右孩子的索引。
    • 函数通过遍历输入的节点信息,填充tree结构体数组,并找到根节点的索引后返回。
  2. 判断两棵树是否同构的函数 (Isomorphism()):

    • 这是一个递归函数,接受两个参数,分别为两棵树的根节点索引。
    • 通过对比两棵树的各个节点数据和子节点结构,确定它们是否同构。
// 构建树的函数
int buildTree(tree* t);
// 判断两棵树是否同构的递归函数
int Isomorphism(int root1, int root2);

 主函数调用buildTree函数构建树形结构

int main()
{
    int r1, r2;
    
    // 分别构建两棵树
    r1 = buildTree(T1);
    r2 = buildTree(T2);
    
    // 如果两棵树同构,打印"Yes"
    if (Isomorphism(r1, r2)) 
    {
        printf("Yes\n");
    }
    // 否则打印"No"
    else
    {
        printf("No\n");
    }

    return 0;
}

构建树的函数 

int buildTree(tree* t)
{
    int root = null, i;
    int n;
    char cleft, cright;
    
    // 输入节点数量
    scanf("%d", &n);
    
    // 如果节点数量大于零
    if (n > 0)
    {
        // 初始化检查数组
        memset(check, 0, sizeof(check));
        
        // 遍历所有节点,输入节点数据及左右子节点索引
        for (i = 0; i < n; i++)
        {
            // 忽略换行符
            getchar();
            
            // 输入当前节点的数据及左右子节点索引
            scanf("%c %c %c", &t[i].data, &cleft, &cright);
            
            // 处理左子节点
            if (cleft!= '-') 
            {
                t[i].left = cleft - '0';   // 将字符形式的索引转为整数
                check[t[i].left] = 1;   // 标记此子节点已被访问
            } 
            else 
                t[i].left = null;       // 空节点
            
            // 处理右子节点
            if (cright!= '-') 
            {
                t[i].right = cright - '0';  // 将字符形式的索引转为整数
                check[t[i].right] = 1;  // 标记此子节点已被访问
            } 
            else 
            {
                t[i].right = null;      // 空节点
            }
        }
        
        // 找到根节点
        for (i = 0; i < n; i++)
        {
        	//没有被访问过
            if (!check[i]) 
			{
			    break;
			}
 		}
        // 返回根节点索引
        root = i;
    }
    
    // 返回根节点索引
    return root;
}

 memset(check, 0, sizeof(check));  :
这里使用memset函数清空check数组,准备记录哪些节点已经被访问过。 

下面是判断两棵树是否同构的算法:

int Isomorphism(int root1, int root2)
{
    // 如果两个根节点都为空,返回真
    if (root1 == null && root2 == null)
    {
        return 1;
    }
     // 如果两个根节点不都为空
    else
    {
    	// 如果只有一个根节点为空,返回假
        if (root1 == null && root2!= null || root1!= null && root2 == null)
        {
            return 0;
        }
     
        else
        {
        	// 如果两个根节点都不为空且数据不同,返回假
            if (T1[root1].data!= T2[root2].data)
            {
                return 0;
            }
            // 如果两个根节点数据相同,继续比较子节点
            else
            {
                // 如果两个根节点都没有左子节点,只比较右子节点
                if (T1[root1].left == null && T2[root2].left == null)
                {
                    return Isomorphism(T1[root1].right, T2[root2].right);
                }
                // 如果两个根节点都有左子节点且数据相同,分别比较左右子节点
                else
                {
                    if (T1[root1].left!= null && T2[root2].left!= null && T1[T1[root1].left].data == T2[T2[root2].left].data)
                    {
                        return Isomorphism(T1[root1].left, T2[root2].left) && Isomorphism(T1[root1].right, T2[root2].right);
                    }
                    // 如果两个根节点都有左子节点但数据不同,交换左右子节点进行比较
                    else
                    {
                        return Isomorphism(T1[root1].right, T2[root2].left) && Isomorphism(T1[root1].left, T2[root2].right);
                    }
                }
            }
        }
    }
}

完整代码附上: 

#include <stdio.h>
#include <string.h>

// 定义最大树的大小
#define MAXTREE 10
// 定义空节点的标识
#define null -1

// 树结构体
typedef struct tree
{
    char data;       // 节点数据
    int left;        // 左子节点索引
    int right;       // 右子节点索引
} tree;

// 全局数组用于存放两个树的节点信息
tree T1[MAXTREE], T2[MAXTREE];
// 检查数组,用于标记已访问过的节点
int check[MAXTREE];

// 构建树的函数
int buildTree(tree* t);
// 判断两棵树是否同构的递归函数
int Isomorphism(int root1, int root2);

int main()
{
    int r1, r2;
    
    // 分别构建两棵树
    r1 = buildTree(T1);
    r2 = buildTree(T2);
    
    // 如果两棵树同构,打印"Yes"
    if (Isomorphism(r1, r2)) 
    {
        printf("Yes\n");
    }
    // 否则打印"No"
    else
    {
        printf("No\n");
    }

    return 0;
}

// 构建树的函数实现
int buildTree(tree* t)
{
    int root = null, i;
    int n;
    char cleft, cright;
    
    // 输入节点数量
    scanf("%d", &n);
    
    // 如果节点数量大于零
    if (n > 0)
    {
        // 初始化检查数组
        memset(check, 0, sizeof(check));
        
        // 遍历所有节点,输入节点数据及左右子节点索引
        for (i = 0; i < n; i++)
        {
            // 忽略换行符
            getchar();
            
            // 输入当前节点的数据及左右子节点索引
            scanf("%c %c %c", &t[i].data, &cleft, &cright);
            
            // 处理左子节点
            if (cleft!= '-') 
            {
                t[i].left = cleft - '0';   // 将字符形式的索引转为整数
                check[t[i].left] = 1;   // 标记此子节点已被访问
            } 
            else 
                t[i].left = null;       // 空节点
            
            // 处理右子节点
            if (cright!= '-') 
            {
                t[i].right = cright - '0';  // 将字符形式的索引转为整数
                check[t[i].right] = 1;  // 标记此子节点已被访问
            } 
            else 
            {
                t[i].right = null;      // 空节点
            }
        }
        
        // 找到根节点
        for (i = 0; i < n; i++)
        {
        	//没有被访问过
            if (!check[i]) 
			{
			    break;
			}
 		}
        // 返回根节点索引
        root = i;
    }
    
    // 返回根节点索引
    return root;
}

// 判断两棵树是否同构的递归函数实现
int Isomorphism(int root1, int root2)
{
    // 如果两个根节点都为空,返回真
    if (root1 == null && root2 == null)
    {
        return 1;
    }
     // 如果两个根节点不都为空
    else
    {
    	// 如果只有一个根节点为空,返回假
        if (root1 == null && root2!= null || root1!= null && root2 == null)
        {
            return 0;
        }
     
        else
        {
        	// 如果两个根节点都不为空且数据不同,返回假
            if (T1[root1].data!= T2[root2].data)
            {
                return 0;
            }
            // 如果两个根节点数据相同,继续比较子节点
            else
            {
                // 如果两个根节点都没有左子节点,只比较右子节点
                if (T1[root1].left == null && T2[root2].left == null)
                {
                    return Isomorphism(T1[root1].right, T2[root2].right);
                }
                // 如果两个根节点都有左子节点且数据相同,分别比较左右子节点
                else
                {
                    if (T1[root1].left!= null && T2[root2].left!= null && T1[T1[root1].left].data == T2[T2[root2].left].data)
                    {
                        return Isomorphism(T1[root1].left, T2[root2].left) && Isomorphism(T1[root1].right, T2[root2].right);
                    }
                    // 如果两个根节点都有左子节点但数据不同,交换左右子节点进行比较
                    else
                    {
                        return Isomorphism(T1[root1].right, T2[root2].left) && Isomorphism(T1[root1].left, T2[root2].right);
                    }
                }
            }
        }
    }
}

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/904032.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

「Mac畅玩鸿蒙与硬件13」鸿蒙UI组件篇3 - TextInput 组件获取用户输入

在鸿蒙应用开发中,TextInput 组件用于接收用户输入,适用于文本、密码等多种输入类型。本文详细介绍鸿蒙 TextInput 组件的使用方法,包括输入限制、样式设置、事件监听及搜索框应用,帮助你灵活处理鸿蒙应用中的用户输入。 关键词 TextInput 组件用户输入输入限制事件监听搜索…

单元测试详解

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 为什么需要单元测试&#xff1f; 从产品角度而言&#xff0c;常规的功能测试、系统测试都是站在产品局部或全局功能进行测试&#xff0c;能够很好地与用户的需…

如何从PPT中导出600dpi的高清图

Step1. 修改PPT注册表 具体过程&#xff0c;参见如下链接&#xff1a;修改ppt注册表&#xff0c;导出高分辨率图片 Step2. 打开PPT&#xff0c;找到自己想要保存的图&#xff0c;选中图像&#xff0c;查看图像尺寸并记录 Step3. 重新新建一个PPT&#xff0c;并根据记录的图片…

「Mac畅玩鸿蒙与硬件7」鸿蒙开发环境配置篇7 - 使用命令行工具和本地模拟器管理项目

本篇将讲解在 macOS 上配置 HarmonyOS 开发环境的流程&#xff0c;聚焦 hvigorw 命令行工具的使用。我们将以创建 HelloWorld 项目为例&#xff0c;演示使用 hvigorw 进行项目构建、清理操作&#xff0c;并通过 DevEco Studio 的本地模拟器进行预览&#xff0c;帮助提升项目开发…

Linux基础—基础命令及相关知识5(ubuntu网络配置)

网络的配置方法 centos网络配置 centos的网卡位置 /etc/sysconfig/network-scripts/ifcfg-ens33(centos网卡文件) bootproto表示获得IP地址的方式是静态的还是动态 onboot表示启动系统时是否激活该网络接口 设置IP地址&#xff0c;子网掩码&#xff0c;网关&#xff0c;dns…

LabVIEW开发的控制阀监控与维护系统

LabVIEW开发一套自动测试软件&#xff0c;用于控制阀的实时监控、数据采集、维护管理以及报警通知。此系统的目标是通过便捷的操作界面、可靠的通信接口和高效的数据管理&#xff0c;为工厂设备管理提供全面的支持。 1. 项目需求 目标是实现一个控制阀管理系统&#xff0c;能够…

第7章 利用CSS和多媒体美化页面作业

2.用表格布局页面&#xff0c;利用CSS技术&#xff0c;及添加多媒体&#xff0c;制作并美化“心灵之音”页面。 浏览效果如下&#xff1a; 实例代码如下&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8"><title>心灵…

Python中的数据可视化:Matplotlib基础与高级技巧

Python中的数据可视化&#xff1a;Matplotlib基础与高级技巧 数据可视化是数据分析和数据科学中不可或缺的一部分。通过图表&#xff0c;我们可以更直观地观察数据的分布和趋势。Matplotlib作为Python最基础、也是最广泛使用的绘图库之一&#xff0c;不仅支持多种常用图表&…

‘cmd‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。

报错描述&#xff1a; 我在使用python执行一个spark任务时&#xff0c;一直报如下错误&#xff0c;检查电脑上所有的环境变量后发现都配置正确&#xff0c;但还是一直报cmd 不是内部或外部命令&#xff0c;也不是可运行的程序这个错误&#xff0c;如果你也有这样的情况&#x…

【网络】传输层协议TCP

目录 四位首部长度 序号 捎带应答 标记位 超时重传机制 连接管理机制&#xff08;RST标记位&#xff09; 三次握手及四次挥手的原因 TCP的全称是传输控制协议&#xff08;Transmission Control Protocol&#xff09;&#xff0c;也就是说&#xff0c;对于放到TCP发送缓冲…

【优选算法篇】前缀之序,后缀之章:于数列深处邂逅算法的光与影

文章目录 C 前缀和详解&#xff1a;基础题解与思维分析前言第一章&#xff1a;前缀和基础应用1.1 一维前缀和模板题解法&#xff08;前缀和&#xff09;图解分析C代码实现易错点提示代码解读题目解析总结 1.2 二维前缀和模板题解法&#xff08;二维前缀和&#xff09;图解分析C…

采用STM32CubeMX和HAL库的定时器应用实例

目录 STM32的通用定时器配置流程 定时器应用的硬件设计 定时器应用的软件设计 1. 通过STM32CubeMX新建工程 通过STM32CubeMX新建工程的步骤如下&#xff1a; 2. 通过Keil MDK实现工程 通过Keil MDK实现工程的步骤如下&#xff1a; STM32的通用定时器配置流程 通用定时器…

开源一套基于若依的wms仓库管理系统,支持lodop和网页打印入库单、出库单的源码

大家好&#xff0c;我是一颗甜苞谷&#xff0c;今天分享一款基于若依的wms仓库管理系统&#xff0c;支持lodop和网页打印入库单、出库单的源码。 前言 在当今快速发展的商业环境中&#xff0c;库存管理对于企业来说至关重要。然而&#xff0c;许多企业仍然依赖于传统的、手动…

算法实现 - 快速排序(Quick Sort) - 理解版

文章目录 算法介绍算法分析核心思想三个版本运行过程挖坑法Hoare 原版前后指针法 算法稳定性和复杂度稳定性时间复杂度平均情况O(nlogn)最差情况O( n 2 n^2 n2) 空间复杂度 算法介绍 快速排序是一种高效的排序算法&#xff0c;由英国计算机科学家C. A. R. Hoare在1960年提出&a…

C语言指针的介绍

零.导言 在日常生活中&#xff0c;我们常常在外出时居住酒店&#xff0c;细心的你一定能发现酒店不同的房间上有着不同的门牌号&#xff0c;上面写着像308&#xff0c;512之类的数字。当你定了酒店之后&#xff0c;你就会拿到一个写有门牌号的钥匙&#xff0c;凭着钥匙就能进入…

聊聊解构的那些事

#我们都知道es6出了个新特性&#xff0c;支持解构&#xff0c;使用过的人可能都觉得挺简单的&#xff0c;但有一些小点&#xff0c;只有使用中留意了或者踩坑了才发现我们认识的还很浅# 解构定义 允许按照一定模式&#xff0c;从数组和对象中提取值&#xff0c;对变量进行赋值…

Qt Designer客户端安装和插件集(pyqt5和pyside2)

GitHub - PyQt5/QtDesignerPlugins: Qt Designer PluginsQt Designer Plugins. Contribute to PyQt5/QtDesignerPlugins development by creating an account on GitHub.https://github.com/PyQt5/QtDesignerPlugins 一、下载客户端 https://github.com/PyQt5/QtDesigner/rel…

Idea常见插件(超级实用)

文章目录 Idea好用的插件推荐Idea插件安装Chinese(中文版)Alibaba Java Coding Guidelines&#xff08;代码规范&#xff09;Auto Filling Java Arguments&#xff08;自动补全参数&#xff09;CamelCase&#xff08;变量名称格式转换&#xff09;CodeGeeX&#xff08;智能&…

Windows 下实验视频降噪算法 MeshFlow 详细教程

MeshFlow视频降噪算法 Meshflow 视频降噪算法来自于 2017 年电子科技大学一篇高质量论文。 该论文提出了一个新的运动模型MeshFlow&#xff0c;它是一个空间平滑的稀疏运动场 (spatially smooth sparse motion field)&#xff0c;其运动矢量 (motion vectors) 仅在网格顶点 (m…

WPF+MVVM案例实战(三)- 动态数字卡片效果实现

1、创建项目 打开 VS2022 &#xff0c;新建项目 Wpf_Examples&#xff0c;创建各层级文件夹&#xff0c;安装 CommunityToolkit.Mvvm 和 Microsoft.Extensions.DependencyInjectio NuGet包,完成MVVM框架搭建。搭建完成后项目层次如下图所示&#xff1a; 这里如何实现 MVVM 框…