判断是否是同一颗二叉搜索树

 给定一个插入序列就可以唯一确定一个平衡二叉树,但是,一个给定的平衡二叉树却可以由不同的插入序列得到。
 比如按照序列{2,1,3}与序列{2,3,1}插入初始为空的二叉搜索树中,将得到相同的二叉平衡树。强调内容


那么我们应该怎么判断输入的不同序列是否生成的是同一颗二叉搜索树呢?

有一下三种方式:

1.建立搜索树

 根据两个序列分别建立两个搜索树,在去比较两个树是否一样。

2.不建立搜索树

首先比较序列的第一个元素是否相同,如果不相同,则说明两个序列对应的一定不是同一个树,如果相同,说明两个序列的根元素是相同的。然后可以把后边的元素分成两堆(比第一个元素小的,比第一个元素大的),分类的时候元素的顺序是不能改变的。
  比如序列1{3,1,2,4}与序列2{3,4,1,2}首先判断第一个元素是相等的,则把后边的元素分类。序列1变为{**1,2,**3,**4**},序列2变为{**3,1,**2,**4**},比较可得两个序列对应的是同一个二叉搜索树。
  又如{3,1,2,4}{3,2,4,1} 这两个序列,经过变化之后为{1,2,3,4},{2,1,3,4} 可以得到前两个的元素顺序是不相同的,所以这两个序列对应的搜索树是不相同的。

3.建立一个树,在判断其他序列是否与该树相同。
3.1 搜索树表示方法
typedef struct TreeNode *Tree;
struct TreeNode
{
    ElementType v;
    Tree left,right;
    int flag;
};

v表示的是在结构体中存储的数据,类型为ElementType,left,right表示的是左右孩子节点的地址。flag是作为一个节点的标记,默认为0。

3.2 建立搜索树
 首先需要读入序列的长度N,与需要判断序列的个数L。然后根据N个元素去建立搜索树T。最后依据树T去判断后边的L个序列是否能与树T形成同一个搜索树。

需要设计的主要函数有:

  • 读取数据建树 MakeTree(int N);
  • 判断一个序列是否与T构成一样的树(Judge(Tree T,int N));

    main函数主要框架构建:

void main()
{
    int N,L,i;
    Tree T;
    scanf("%d",&N);
    while(N)
    {
        scanf("%d",&L);
        T = MakeTree(N);//建树
        for(i = 0;i<L;i++)//有L个序列需要比较
        {
            if(Judge(T,N))//满足条件,表示是同一个序列
                printf("Yes\n");
            else 
                printf("No\n");
            Reset(T);//序列比较结束,当比较下一个序列的时候,把当前做的标记清除。
        }
        FreeTree(T);//释放树
        scanf("%d",&N);//继续下一批序列的比较
    }
}
3.3判断一个序列是否与搜索树相同
当一个树T建立之后,如何判断一个序列对应的搜索树是否跟T相同呢?

方法: 在树T中按顺序搜索序列中的的每个数。

  • 如果每次搜索所经过的节点都出现过,则表示相同
  • 搜索中遇到前面没有遇到的节点,则表示不一致。

这里写图片描述

对应的函数实现:

int check(Tree T,int V)
{
    if(T->flag)
    {
        if(T->v > V)
            check(T->left,V);
        else if(T->v < V)
            check(T->right,V);
        else
            return 0;
    }
    else
    {
        if(T->v == V)
        {
            flag == 1;
            return 1;   
        }
        else // 在标记是0 的条件下,数值也不相同,导致在序列构建树的时候,该节点会不一致。
        return 0;
    } 
}

Judge(Tree T ,int N)函数的具体实现:

int Judge(Tree T,int N)//有bug
{
    int V,i;
    scanf("%d",&V);
    if(T->v != V)return 0;
    else T->flag = 1;
    for(i = 1;i<N;i++)
    {
        scanf("%d",&V);
        if(!check(T,V))return 0;
    }
    else return 1;
}

然后在这种情况下,Judge函数会有一个bug出现,当一个序列还没有输入完全的时候,出现了不一致,导致了后边的数值无法输入。所以在Judge函数中引入一个标记,确保在不一致的时候,也可以把后边的序列输入完全。


更改如下:

int Judge(Tree T,int N)
{
    int V,i;
    int flag = 0;//标记默认为 0,当序列与T出现不一致的时候,设为 1 
    scanf("%d",&V);
    if(T->v != V)flag = 1;//根节点不同,把标记设为 1 
    else 
        T->flag = 1;//注意与函数中的标记做区分
     for(i = 1;i<N;i++)
    {
        scanf("%d",&V);
        if((!flag)&&(!check(T,V))) flag = 1;
    }
    if(flag)
        return return 0;
    return 1;
}

全部代码:
#include<stdio.h>
#include<stdlib.h>
typedef struct TreeNode *Tree;
struct TreeNode
{
    ElementType v;
    Tree left,right;
    int flag;
}

void main()
{
    int N,L,i;
    Tree T;
    scanf("%d",&N);//输入二叉树的节点数。
    while(N)
    {
        scanf("%d",&L);//L表示的是有几个需要不比较的数目
        T = MakeTree(N);
        for(i = 0;i<L;i++)
        {
            if(Judge(T,N))printf("Yes\n");
            else printf("No\n");
            Reset(T);//清除标记 
        }
        FreeTree(T);
        scanf("%d",&N); 
    } 
}
int Judge(Tree T,int N)//当发现出现不一致的时候,也要把后边的数据输入完,不能直接返回。所以添加了flag标记。 
{
    int i ,V;
    int flag = 0;//flag = 1;表示的是已经出现了不一致。 

    scanf("%d",&V);
    if(V != T->v ) flag = 1;
    else T->flag = 1;

    for(i = 1;i<N;i++)
    {
        scanf("%d",&V);
        //if(!check(T,V))return 0;出现不一致,不可以直接返回,要把后边的数据输入完
        if((!flag) && (!check(T,V))) flag = 1;
    }
    if(flag) return 0;
    else return 1;
}

int check(Tree T,int V)
{
    if(T->flag)
    {
        if(T->v > V) check(T->Left,V);
        else if(T->v < V)check(T->Right,V);
        else return 0;
    }
    else
    {
        if(T->v == V)
        {
            T->flag = 1;
            return 1;
        }
        else return 0;
    }
}

//建立二叉树
Tree MakeTree(int N)//n表示的是这颗树有多少个节点 
{
    Tree T;
    int V i;
    scanf("%d",&V);//输入第二个节点的数值,去建立一个树
    Tree = NewNode(V);//建立根节点
    for(i = 1;i<N;i++)
    {
        scanf("%d",&V);//先节点的数值 
        T = Insert(T,V);//在根节点上插入节点 
    }
    return T; 
}
//插入节点函数
Tree Insert(Tree T,int V)
{
    if(!T)T = NewNode(V);//
    else
    {
        if(T->v > V)
        {
            T->left = Insert(T,V);  
        }
        else
            T->right = Insert(T,V); 
    }
    return T;
} 


//建立二叉树的每一个节点
Tree NewNode(int V)
{
    Tree T = (Tree)malloc(sizeof(struct TreeNode));
    T->v = V;
    T->left = T->right = NULL;
    T->flag = 0;
    return T;  
} 
//清楚标记 
void Reset(Tree T)
{
    if(T->left)Reset(T->left);
    if(T->right)Reset(T->right);
    T->flag = 0;
}
//释放内存空间
void FreeTree(Tree T)
{
    if(T->left) FreeTree(T->left);
    if(T->right)FreeTree(T->right);
    free(T);    
} 
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值