数据结构刷题笔记1——是否同一棵二叉搜索树

04-树4 是否同一棵二叉搜索树 (25 分)

题目来源:浙江大学数据结构MOOC配套习题(PTA)

给定一个插入序列就可以唯一确定一棵二叉搜索树。然而,一棵给定的二叉搜索树却可以由多种不同的插入序列得到。例如分别按照序列{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. 建两棵树,根据序列建两棵树再判断两棵树是否一致;
  3. 建一棵树,把判断基准建立为一棵基准树,其它的数据放进来和这棵树比较

本文采用第三种方法——建立一棵树然后新的序列与这棵树作比较
代码如下

#include <stdio.h>
#include <stdlib.h>

typedef struct TreeNode *Tree;
struct TreeNode
{
    Tree Left,Right;//用两个指针来指向左右子树
    int data,flag;//data来存放这个节点的数据,flag用来判断是否访问过该节点
};

Tree BuildTree(int N);
Tree NewNode(int V);
Tree Insert(Tree T,int V);
char Judge(Tree T,int N);
char check(Tree T,int N);
void FreeTree(Tree T);
void ResetT(Tree T);

int main()
{
    int N,i,L;
    Tree T;
    scanf("%d",&N);
    while(N)//当N为0时返回
    {
        scanf("%d",&L);
        T = BuildTree(N);//建立二叉搜索树
        for(i = 0; i < L; i++)//多组数据,使用读入的L来控制读入的数据组数
        {
            if(Judge(T,N)) printf("Yes\n");//判断是否是一棵树
            else printf("No\n");
            ResetT(T);//将T初始化
        }
        FreeTree(T);//判断完成后释放当前树
        scanf("%d",&N);
    }
    return 0;
}

Tree BuildTree(int N)
{
    int i,V;
    Tree T;
    scanf("%d",&V);
    T = NewNode(V);//开辟第一个节点
    for(i=1;i<N;i++)
    {
        scanf("%d",&V);
        T = Insert(T,V);//后续节点的插入(保证插入完成后该树为二叉搜索树)
    }
    return T;
}

Tree NewNode(int V)
{
    Tree T = (Tree)malloc(sizeof(struct TreeNode));//开辟新节点
    T -> data = V;
    T -> Left = T->Right = NULL;
    T -> flag = 0;//初始化操作
    return T;
}

Tree Insert(Tree T,int V)
{
    if(!T) T = NewNode(V);//查找到空节点时开辟新节点并插入
    else{
        if(T->data > V)//此节点数据大于要插入的数据时向左插入
            T->Left = Insert(T->Left,V);
        else
            T->Right = Insert(T->Right,V);
    }
    return T;
}
char Judge(Tree T,int N)
{
    int i,V,Jflag = 0;//使用Jflag来保证在中途判断出不是同一棵树后仍能继续读数据和判断
    scanf("%d",&V);
    if( V != T->data) Jflag = 1;
    else T->flag = 1;
    for(i=1;i<N;i++)
    {
        scanf("%d",&V);
        if((!check(T,V)) && (!Jflag)) Jflag = 1;
    }
    if(Jflag) return 0;
    else return 1;
}

char check(Tree T,int V)
{
    if(T->flag)//当这个节点被访问过
    {
        //要判断的数据和这个节点不等时根据大小关系向左向右判断
        if(T->data>V) return check(T->Left,V);
        else if(T->data<V) return check(T->Right,V);
        else return 0;//如果这个节点被访问过且数据和要判断的数据相同说明不是
    }
    else{
        if(V == T->data){//未访问过该节点且该节点数据和需要判断的数据相等
            T->flag = 1;
            return 1;
        }
        else return 0;
    }
}

void FreeTree(Tree T)
{//释放判断的基准树
    if(T->Right) FreeTree(T->Right);
    if(T->Left) FreeTree(T->Left);
    free(T);
}

void ResetT(Tree T)
{//判断完成后的树的初始化
    if(T->Right) ResetT(T->Right);
    if(T->Left) ResetT(T->Left);
    T->flag = 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Oath丶forever

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值