PTA 7-4 是否为同一颗二叉树(三种解法)

PTA 7-4 是否为同一颗二叉树(三种解法)

清晰思路参照: mooc → 浙大《数据结构》课程 → 第四讲 树(中)小白专场

题目详细:

给定一个插入序列就可以唯一确定一棵二叉搜索树。然而,一棵给定的二叉搜索树却可以由多种不同的插入序列得到。例如分别按照序列{2, 1, 3}和{2, 3, 1}插入初始为空的二叉搜索树,都得到一样的结果。于是对于输入的各种插入序列,你需要判断它们是否能生成一样的二叉搜索树。

输入格式:

输入包含若干组测试数据。每组数据的第1行给出两个正整数N (≤10)和L,分别是每个序列插入元素的个数和需要检查的序列个数。第2行给出N个以空格分隔的正整数,作为初始插入序列。最后L行,每行给出N个插入的元素,属于L个需要检查的序列。

简单起见,我们保证每个插入序列都是1到N的一个排列。当读到N为0时,标志输入结束,这组数据不要处理。

输出格式:

对每一组需要检查的序列,如果其生成的二叉搜索树跟对应的初始序列生成的一样,输出“Yes”,否则输出“No”。

输入样例:

4 2
3 1 4 2
3 4 1 2
3 2 4 1
2 1
2 1
1 2
0

输出样例:

Yes
No
No

代码部分

1.分别建两颗搜索树的判别方法

根据两个序列分别建树,再判别树是否一样

#include<stdio.h>
#include<stdlib.h>
#define Max 10

typedef struct BNode *BST;
struct BNode{
	int num;
	BST Left;
	BST Right;
};

BST Insert(BST T,int a)
{
	if(!T)//空结点时即为要插入的地方,建立新结点
	{
		BST Node = (BST)malloc(sizeof(BST));
		Node->num = a;
		Node->Left = Node->Right = NULL;
		return Node;
	}
	else{
		if(T->num>a) T->Left=Insert(T->Left,a); //小于根节点,左插
		else T->Right = Insert(T->Right,a);//大于根节点,右插
	}
	return T;
}

BST BuildTree(int N)
{
	BST T = (BST)malloc(sizeof(BST));
	scanf("%d",&T->num);//建立根结点
	T->Left=T->Right=NULL;
	for(int i =1;i<N;i++){
		int a;
		scanf("%d",&a);
		T = Insert(T,a);//建立二叉搜索树
	} 
	return T;
}

int isSameBST(BST T,BST test)
{
	int flag = 1;
	if(T&&test){
		if(T->num != test->num) return 0;//两个结点的值不同,返回0
		flag = isSameBST(T->Left,test->Left);//递归判断左子树
			if(!flag) return 0;
		flag = isSameBST(T->Right,test->Right);//递归判断右子树
			if(!flag) return 0;
	}
	return flag;
}


int main()
{
	while(1){
		int N;
		scanf("%d",&N);
		if(N==0) break;	//输入0,程序终止
		int n_test;
		scanf("%d",&n_test);
		BST T = BuildTree(N); //建立二叉搜索树
		for(int i=0;i<n_test;i++){
			BST test = BuildTree(N); //建立要测试的二叉搜索树
			int flag = isSameBST(T,test); //判断是否为同一颗BST树
			if(flag) printf("Yes\n");
			else printf("No\n");
		}
	}
	return 0;
}

结果展示:
在这里插入图片描述

2.不建树的判别方法

#include<stdio.h>
#include<stdlib.h>
#define MAX 10

int Judge(int List[],int Test[],int N)
{
	if(List[0]!=Test[0])return 0;
	int flag = 1;
	int root = List[0];
	int List_L[MAX],List_R[MAX],Test_L[MAX],Test_R[MAX];
	int L1=0,L2=0,R1=0,R2=0;
	for(int i=1;i<N;i++) //按照大于或小于根节点,分为左右子树
	{
		if(List[i]<root) List_L[L1++]=List[i];
		if(List[i]>root) List_R[R1++] = List[i];
		if(Test[i]<root) Test_L[L2++]=Test[i];
		if(Test[i]>root) Test_R[R2++]=Test[i];
	} 
	if(L1>0&&L2>0&&L1==L2) if(!Judge(List_L,Test_L,L1)) return 0;
	if(R1>0&&R2>0&&R1==R2) if(!Judge(List_R,Test_R,R1)) return 0;
	return 1;
}

int main()
{
	while(1)
	{
		int N,n_test;
		scanf("%d",&N);
		if(!N) break;
		scanf("%d",&n_test);
		int List[MAX],Test[MAX];
		for(int i=0;i<N;i++) scanf("%d",&List[i]);
		for(int i=0;i<n_test;i++){
			int flag = 0;
			for(int j=0;j<N;j++) scanf("%d",&Test[j]);
			flag = Judge(List,Test,N);
			if(flag) printf("Yes\n");
			else printf("No\n");
		}
	}
	return 0;
}

自己觉得应该有更精简的写法,但是目前实力不太可,有些许的繁琐难懂/(ㄒoㄒ)/~~

结果展示:
在这里插入图片描述

3.建一棵树,再判别其他序列是否与该树一致

#include<stdio.h>
#include<stdlib.h>
#define MAX 10

typedef struct TNode* Tree;
struct TNode{
	int num;
	Tree Left;
	Tree Right;
	int check; //标记符 
};

Tree NewNode(int a)
{
	Tree T = (Tree)malloc(sizeof(struct TNode));
	T->num = a;
	T->Left =T->Right = NULL;
	T->check = 0;
	return T;
 } 

Tree Insert(Tree T,int a)
{
	if(!T) T = NewNode(a);
	else{
		if(T->num>a) T->Left = Insert(T->Left,a);
		else T->Right = Insert(T->Right,a);
	}
	return T;
}

Tree BuildTree(int N)//建树过程基本一致
{
	Tree T ;
	int a;
	scanf("%d",&a);
	T = NewNode(a);
	for(int i=1;i<N;i++){
		scanf("%d",&a);
		T = Insert(T,a);
	}
	return T;
}

int check(Tree T,int a)
{
	if(T->check) //该结点已经判断过
	{
		if(T->num a) return check(T->Left,a); //大于判断值,找左子树
		else if(T->num < a) return check(T->Right,a); //小于判断值,找右子树
		else return 0;
	}
	else//该结点没有遍历过
	{
		if(T->num == a)//等于判断值,树的标记符记为1
		{
			T->check =1;
			return 1;
		}
		else return 0;//否则,返回0
	}
}

int isSame(Tree T,int N)
{
	int flag = 0;//设置flag,要保证所有数字都输入进去,防止干扰下一个测试树的判断
	int a = 0;
	scanf("%d",&a);
	if(T->num != a) flag =1;
	else T->check = 1;
	for(int i=1;i<N;i++){
		scanf("%d",&a);
		if((!flag) && (!check(T,a)) ) flag =1;
	}
	
	return flag?0:1;
}

void Reset(Tree T) // 判断完一组测试数列后,对照树标记符记为0
{
	if(T->Left) Reset(T->Left);
	if(T->Right) Reset(T->Right);
	T->check = 0; 
}

void FreeTree(Tree T) // 释放树
{
	if(T->Left) FreeTree(T->Left);
	if(T->Right) FreeTree(T->Right);
	free(T);
}

int main()
{
	while(1)
	{
		int N, n_test;
		scanf("%d",&N);
		if(!N) break;
		scanf("%d",&n_test);
		Tree T = BuildTree(N);
		for(int i=0;i<n_test;i++){
			int flag =0;
			flag = isSame(T,N);
			if(flag) printf("Yes\n");
			else printf("No\n");
			Reset(T);
		}
		FreeTree(T);
	}
	return 0;	
} 

基本是照着老师的代码敲下来的

结果展示:
在这里插入图片描述

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值