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):不建树的判别方法
树T{3,1,2,4}和{3,4,1,2}
分成比根节点小的和比根节点大的 按照原来的顺序
第一组 {1 2 }3 {4}
第二组 {1 2 }3 {4}
3):建立一颗树 再判别序列
方法:在树T中按照顺序搜索序列 3 2 4 1的每个数

  • 如果每次搜索所经过的结点在前面均为出现过 则一致
  • 否则(某次搜索中遇到前面未出现的结点) 则不一致
#include<iostream>
#include<malloc.h>
using namespace std;
//二叉搜索树的结构定义
typedef struct node *tree;
struct node{
    int data;
    tree Lchild;
    tree Rchild;
    int flag;//标记是否经过该结点
};
//构建新节点
tree NewNode(int data)
{
    tree T=(tree)malloc(sizeof(struct node));
    T->Lchild=T->Rchild=NULL;
    T->data=data;
    T->flag=0;
    return T;
}
//二叉搜索树的插入
tree Insert(tree T,int data)
{
    if(!T) T=NewNode(data);//如果是空树 就建立一个新节点
    else{//递归找插入的位置
        if(data>T->data) 	T->Rchild=Insert(T->Rchild,data);
        else T->Lchild=Insert(T->Lchild,data);
    }
    return T;
}
//建立需要比较的二叉搜索树 N为建立节点的个数
tree BuildTree(int N)
{
    tree T;
    int data;
    cin>>data;
    T=NewNode(data);
    for(int i=1;i<N;i++){
        cin>>data;
        T=Insert(T,data);
    }
    return T;
}
/*
按照顺序查找结点 如果经过的结点之前未经过 说明不是同一颗树
(因为结点本应该插在这个未经过的结点的位置 但现在却经过)
*/
int Check(tree T,int data)
{
    if(T->flag){//flag==1表示访问过的点
        if(data>T->data)Check(T->Rchild,data);
        else if(data<T->data) Check(T->Lchild,data);
        else return 0;//碰到了两个一样的值
    }else{
        if(data==T->data){
            T->flag=1;
            return 1;
         }else return 0;//遇到了以前没遇到的点
      }
}
int judge(tree T,int N)
{
    int data,flag=0;//0表示目前符合一致
    cin>>data;
    if(T->data!=data) flag=1;//树根不一致 
    else T->flag=1;//根节点标记为1
    for(int i=1;i<N;i++){
        cin>>data;
        if(!flag&&!Check(T,data))flag=1;//设置flag 原因是 即使判断了不是同一颗树 也要将剩下的结点接受完 防止影响下一组数据
    }
    if(flag) return 0;
    else return 1;
}
//重设flag
void Reset(tree T)
{
    if(T->Lchild) Reset(T->Lchild);
    if(T->Rchild) Reset(T->Rchild);
    T->flag=0;
}
//重设树
void FreeTree(tree T)
{
    if(T->Lchild) FreeTree(T->Lchild);
    if(T->Rchild) FreeTree(T->Rchild);
    free(T);
}
int main()
{
    int N,L;
    tree T;
    cin>>N;
    while(N){
        cin>>L;
        T=BuildTree(N);
        for(int i=0;i<L;i++){
            if(judge(T,N)) cout<<"Yes"<<endl;
            else cout<<"No"<<endl;
            Reset(T);
         }
         FreeTree(T);
         cin>>N;
     }
     return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值