PTA 04-树4 是否同一棵二叉搜索树
给定一个插入序列就可以唯一确定一棵二叉搜索树。然而,一棵给定的二叉搜索树却可以由多种不同的插入序列得到。例如分别按照序列{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)建两棵树,比较每一个结点的值
(2)不建树,对每个序列进行划分对比
将小于该结点的放置结点前(不改变原来顺序)
将大于该结点的放置结点后(不改变原来顺序)
e.g.{3124}->{12}3{4}
{3142}->{12}3{4} 相同
{3421}->{21}3{4} 不相同
(3)建一棵树,其他序列去与树进行比较
我们发现规律:
如果序列在搜索原来这颗建好的树时需要访问之前没有访问过的结点,则不是同一颗二叉树。代码中的TreeNode的flag印证了这点
代码
#include<iostream>
using namespace std;
typedef struct TreeNode *Tree;//指向TreeNode类型的指针
struct TreeNode{
int v;
Tree left,right;
int flag;
};
//建立新的结点
Tree NewNode(int v){
Tree New=(Tree)malloc(sizeof(struct TreeNode));
New->v=v;
New->left=NULL;
New->right=NULL;
New->flag=0;
return New;
}
//插入搜索树
Tree Insert(Tree T,int V){
if(!T){//此时结点为空结点
T=NewNode(V);
}else{
if(V>T->v){
T->right=Insert(T->right,V);
}else{
T->left=Insert(T->left,V);
}
}
return T;
}
//建立用于比较的“参考”树
Tree MakeTree(int N){
int V;
Tree T;
scanf("%d",&V);
T=NewNode(V);
for(int i=1;i<N;i++){
scanf("%d",&V);
T=Insert(T,V);
}
return T;
}
//检查某个子序列(数)是否合法
int check(Tree T,int V){
if(T->flag){//flag=1
if(V<T->v){
return check(T->left,V);
}else if(V>T->v){
return check(T->right,V);
}else{//值相同V==T->v且这个点被访问过
return 0;
}
}else{//flag=0
if(T->v==V){//合法查找
T->flag=1;
return 1;
}else{//在搜索的路上找到以前没有访问过的结点->不是同一个树
return 0;
}
}
}
//检查这个序列是否合法
int Judge(Tree T,int N){
int V,flag=1;//flag=1合法
scanf("%d",&V);
if(T->v!=V)//头结点 树根不同
flag=0;//不合法
else{
T->flag=1;//合法,访问
}
for(int i=1;i<N;i++){
scanf("%d",&V);
if(flag&&!check(T,V))
flag=0;//不合法
}
if(flag){
return 1;
}else{
return 0;
}
}
//重置树的flag
void Reset(Tree T){
if(T->left){//有左孩子-递归
Reset(T->left);
}
if(T->right){//有右孩子-递归
Reset(T->right);
}
T->flag=0;//重置这个结点的flag
}
//解放树所占用的内存空间
void Free(Tree T){
if(T->left)
Free(T->left);
if(T->right)
Free(T->right);
free(T);
}
int main(){
int N,L,first=1;//first输出换行
scanf("%d",&N);
while(N){
scanf("%d",&L);
Tree T;
T=MakeTree(N);
for(int i=0;i<L;i++){
if(first){
first=0;
}else{
printf("\n");
}
if(Judge(T,N)){
printf("Yes");
}
else{
printf("No");
}
Reset(T);
}
Free(T);
scanf("%d",&N);
}
}