PTA 树的同构 思路分析及代码解析

本文详细解析了PTA题目'树的同构'的解题思路,包括建树、比较树的同构状态等关键步骤,并提供了具体的C++代码实现,通过递归函数比较两棵树的节点数据和子树结构。文章强调了处理空树情况和正确判断根节点的重要性,以及在代码中避免常见错误的技巧。
摘要由CSDN通过智能技术生成

一、前导

1. 需要掌握的知识

  1. 二叉树
  2. 递归函数的应用

2. 题目信息

  1. 题目来源:PTA / 拼题A
  2. 题目地址:树的同构

二、解题思路分析

1. 题意理解

  1. 输入数据
N		//树1的结点数:随后N行,从0到N-1编号,第i行对应编号第i个结点
A 1 -  //结点值、左子树结点编号、右子树结点编号(-表示空树)
B 3 4
...
2		//树2的结点数
B - 1	//树2的结点信息
A 4 5
...
  1. 输出数据
    两棵树若同构输出Yes,否则输出No
  2. 题意
    判定两棵树是否‘同构’。题目定义了’同构’概念:树1若通过左右子树互换就可以变成树2(互换次数不限),则称两棵树“同构”。

2. 思路分析(重点)

先建树然后再比较

三、具体实现

1. 弯路和bug

  1. 存在树结点为0的场景
  2. 若定义 -1 代表空树,则在判定时需要明确条件
//树1空,树2不空
if(root1==-1 && root2) //错误
if(root1==-1 && root2!=-1) //正确

2. 代码框架(重点)

2.1 采用的数据结构

结构体数组

#define max 10
typedef char ElementType; 
struct BinaryTree
{
	ElementType data;
	int left;
	int right; 
};
struct BinaryTree Tree1[max],Tree2[max];

2.2 程序主体框架

               程序伪码描述
int main()
{	
	1. 建树并找到树根 :树根就是不被其他结点指向的结点 
	2. 比较:考虑所有可能(会调用递归) 
}

2.3 各分支函数

  1. CreatTree( ) 根据输入创建树并返回根结点
typedef int RootNumber;
bool flag[max]={0}; //flag数组用于标定root,初始值均为0
RootNumber CreatTree(int Nodes,struct BinaryTree a[]) //建树并找到根 
{
	char data,left,right; //char类型便于找到空树'-'
	for(int i=0;i<Nodes;i++) 
	{ 
		cin>>data>>left>>right;
		a[i].data=data;	
		if(left=='-')
			a[i].left=Null;
		else
		{
			a[i].left=left-'0';
			flag[a[i].left]=true;//被指向的元素不是树根,因此改变对应的flag值
		}
		if(right=='-')
			a[i].right=Null;
		else
		{
			a[i].right=right-'0';
			flag[a[i].right]=true;
		}		
	}
	for(int j=0;j<Nodes;j++)
		if(!flag[j]) return j;
}
  1. Judge( ) 考虑到所有可能就可以AC
    (1) 一棵空 一棵不空 1*
    (2) 两棵都空 2*
    (3) 两棵都不空
    I.根不同 3*
    II.根相同
    i.左子树空,递归右子树 4*
    ii.左子树根相同
    ii.子树根不同
bool Judge(RootNumber root1,RootNumber root2)
{
	if((root1==Null && root2!=Null) || (root1!=Null && root2==Null))  
		return false;
		
	
	if(root1==Null && root2==Null)
		return true;
		
		
	if(Tree1[root1].data != Tree2[root2].data) 
		return false;
	else //根相同 
	{
		if(Tree1[root1].left==Null && Tree2[root2].left==Null)
			return Judge(Tree1[root1].right,Tree2[root2].right);
		else if( Tree1[Tree1[root1].left].data == Tree2[Tree2[root2].left].data)
			return ( Judge(Tree1[root1].left,Tree2[root2].left) && Judge(Tree1[root1].right,Tree2[root2].right) ) ;
		else if( Tree1[Tree1[root1].left].data != Tree2[Tree2[root2].left].data)
			return ( Judge(Tree1[root1].left,Tree2[root2].right) && Judge(Tree1[root1].right,Tree2[root2].left) );	
	}		
}

3. 完整编码

#include <iostream>
using namespace std; 

#define max 10
#define Null -1 

typedef int OrderNumber;
typedef int RootNumber;
typedef char ElementType; 
struct BinaryTree
{
	ElementType data;
	OrderNumber left;
	OrderNumber right; 
};

struct BinaryTree Tree1[max],Tree2[max];

bool flag[max]={0};
RootNumber CreatTree(int Nodes,struct BinaryTree a[]);
void Default();
void Display(bool flag[]);
bool Judge(RootNumber root1,RootNumber root2);

int main()
{

	int Nodes; int root1,root2; bool result=true;
	 
	cin>>Nodes;
	if(!Nodes) { cout<<"Yes"<<endl; return 0;}
	
	root1=CreatTree(Nodes,Tree1);

	Default();
		
	cin>>Nodes;
	root2=CreatTree(Nodes,Tree2);
	
	result = Judge(root1,root2);
	
	if(result) cout<<"Yes"<<endl;
	else cout<<"No"<<endl; 
	
	return 0;
}

RootNumber CreatTree(int Nodes,struct BinaryTree a[]) //建树并找到根 
{
	char data,left,right; //char类型便于找到空树'-'
	for(int i=0;i<Nodes;i++) 
	{ 
		cin>>data>>left>>right;
		a[i].data=data;	
		if(left=='-')
			a[i].left=Null;
		else
		{
			a[i].left=left-'0';
			flag[a[i].left]=true;//被指向的元素不是树根,因此改变对应的flag值
		}
		if(right=='-')
			a[i].right=Null;
		else
		{
			a[i].right=right-'0';
			flag[a[i].right]=true;
		}		
	}
	for(int j=0;j<Nodes;j++)
		if(!flag[j]) return j;
}

void Default()
{
	for(int i=0;i<max;i++)
		flag[i]=false;
}

bool Judge(RootNumber root1,RootNumber root2)
{
	if((root1==Null && root2!=Null) || (root1!=Null && root2==Null))  
		return false;
		
	
	if(root1==Null && root2==Null)
		return true;
		
		
	if(Tree1[root1].data != Tree2[root2].data) 
		return false;
	else //根相同 
	{
		if(Tree1[root1].left==Null && Tree2[root2].left==Null)
			return Judge(Tree1[root1].right,Tree2[root2].right);
		else if( Tree1[Tree1[root1].left].data == Tree2[Tree2[root2].left].data)
			return ( Judge(Tree1[root1].left,Tree2[root2].left) && Judge(Tree1[root1].right,Tree2[root2].right) ) ;
		else if( Tree1[Tree1[root1].left].data != Tree2[Tree2[root2].left].data)
			return ( Judge(Tree1[root1].left,Tree2[root2].right) && Judge(Tree1[root1].right,Tree2[root2].left) );	
	}		
}

210929 AC代码:题目的核心问题有两个,数据如何存储(结构体数组) + 如何判定(判定root,左右子树用递归)
进步点:有规划,逻辑思维比较清楚
待改进:做题速度慢 + 粗心 + 编码逻辑能力还需提升

#include <iostream>
using namespace std;

#define Max 10
#define Null -1
struct Node
{
	char Value;
	int Left;
	int Right;
};

int CreateTree(struct Node Tree[],int N);
bool Judge(struct Node Tree01[], int Root01, struct Node Tree02[], int Root02);

int main()
{
	struct Node Tree01[Max], Tree02[Max];
	int Root01=-1, Root02=-1;
	int N; 
	
	cin >> N;
	Root01 = CreateTree(Tree01, N);

	cin >> N;
	Root02= CreateTree(Tree02, N);

	bool Result = Judge(Tree01, Root01, Tree02, Root02);
	if (Result)
		cout << "Yes";
	else
		cout << "No";

	return 0;
}

bool Judge(struct Node Tree01[], int Root01, struct Node Tree02[], int Root02)
{
	//1.一棵空 一棵不空
	if ((Root01 == Null && Root02 != Null) || (Root01 != Null && Root02 == Null))
		return false;
		
	//2.两棵都空
	if (Root01 == Null && Root02 == Null)
		return true;	

	// 3.两棵都不空:根不同
	if (Tree01[Root01].Value != Tree02[Root02].Value) //
		return false;
	else //4.两棵都不空:根相同, 左左比较、右右比较 或者 左右比较、右左比较
	{
		int Left01, Left02, Right01, Right02;
		Left01 = Tree01[Root01].Left; Right01 = Tree01[Root01].Right;
		Left02 = Tree02[Root02].Left; Right02 = Tree02[Root02].Right;

		return ( Judge(Tree01, Left01, Tree02, Left02) && 
			   Judge(Tree01, Right01,Tree02, Right02) )
			||
			(Judge(Tree01, Left01, Tree02, Right02)&&
			Judge(Tree01,Right01,Tree02,Left02));
	}
}

int CreateTree(struct Node Tree[], int N)
{
	char Value, Left, Right; 

	bool* a = new bool[N]; //找到TreeRoot

	for (int i = 0; i < N; i++)
		a[i] = true;

	for (int i = 0; i < N; i++) //输入顺序就是结点编号:i=1表示下标为1的结点
	{
		cin >> Value >> Left >> Right;
		Tree[i].Value = Value;

		if (Left == '-')
			Tree[i].Left = Null;
		else
		{
			Tree[i].Left = Left - '0';
			a[Tree[i].Left] = false;
		}
			
		if (Right == '-')
			Tree[i].Right = Null;
		else
		{
			Tree[i].Right = Right - '0';
			a[Tree[i].Right] = false;
		}
	}

	for (int i = 0; i < N; i++)
		if (a[i])
			return i;
	return Null;
}

四、参考资料

浙江大学 陈越、何钦铭老师主讲的数据结构

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值