二叉搜索树 - 九度教程第 36 题

本文介绍了一种算法,用于判断两个数字序列是否能够构成相同的二叉搜索树。通过构建二叉树并比较前序与中序遍历结果,实现序列的匹配验证。

二叉搜索树 - 九度教程第 36 题

题目

时间限制:1 秒 内存限制:32 兆 特殊判题:否
题目描述:
判断两序列是否为同一二叉搜索树序列
输入:
开始一个数 n,(1<=n<=20) 表示有 n 个需要判断,n= 0 的时候输入结束。 接下去一行是一个序列,序列长度小于 10,包含(0~9)的数字,没有重复数字, 根据这个序列可以构造出一颗二叉搜索树。 接下去的 n 行有 n 个序列,每个序列格式跟第一个序列一样,请判断这两个 序列是否能组成同一颗二叉搜索树。
输出:
如果序列相同则输出 YES,否则输出 NO
样例输入:
2
567432
543267
576342
0
样例输出:
YES
NO
来源:
2010 年浙江大学计算机及软件工程研究生机试真题

对输入的数字序列构建二叉排序树,并对它们进行前序和中序的遍历, 依次比较两次遍历结果是否相同,若相同则说明两棵二叉排序树相同,否则不同。

#include <stdio.h>
#include <string.h>

struct Node{
    Node *lchild;
    Node *rchild;
    int c;
}Tree[210];//21*10

int loc;
Node *creat(){
    Tree[loc].lchild=NULL;
    Tree[loc].rchild=NULL;
    return &Tree[loc++];
}

Node *Insert(Node *T, int x){
    if(T==NULL){
        T=creat();
        T->c=x;
        return T;
    }
    if(x < T->c){
        T->lchild=Insert(T->lchild,x);
    }else{
        T->rchild=Insert(T->rchild,x);
    }//由题意不存在相同的情况
    return T;
}

char str1[21],str2[21];
//保存二叉排序树的遍历结果
//将每一颗树的前序遍历得到的字符串与中序遍历得到的
//字符串连接,得到用于比较的遍历结果字符串
int size1,size2;//保存在字符数组中的遍历得到的字符个数
char *str;//当前正在保存的字符串
int *size;//当前正在保存字符串中字符个数

void preOrdet(Node *T){
    str[(*size)++]=T->c + '0';
    //将节点中的字符放入正在保存的字符串中

    if(T->lchild!=NULL){
        preOrdet(T->lchild);
    }
    if(T->rchild!=NULL){
        preOrdet(T->rchild);
    }
}

void inOrder(Node *T){
    if(T->lchild!=NULL){
        inOrder(T->lchild);
    }
    str[(*size)++]=T->c + '0';
    if(T->rchild!=NULL){
        inOrder(T->rchild);
    }
}

int main()
{
    int n;
    char temp[11];
    while(scanf("%d",&n)!=EOF && n!=0){
        scanf("%s",temp);
        loc=0;
        Node *T=NULL;

        for(int i=0;temp[i]!=0;i++){
            T=Insert(T,temp[i]-'0');
            //按顺序将数字插入二叉排序树
        }
        size1=0;//保存在第一个字符串中的字符个数初始化为0
        str=str1;//将正在保存的字符串设定为第一个字符串
        size=&size1;//将正在保存的字符串中的字符个数指针指向size1
        preOrdet(T);//前序遍历
        inOrder(T);//中序遍历
        str1[size1]=0;
        //在第一个字符串的最后一个字符后添加空字符,方便后面使用字符串函数

        while(n-- != 0){//输入n个其他字符串
            scanf("%s",temp);
            Node *T2=NULL;
            for(int i=0;temp[i]!=0;i++){
                T2=Insert(T2,temp[i]-'0');
            }
            size2=0;
            str=str2;
            size=&size2;
            preOrdet(T2);
            inOrder(T2);
            str2[size2]=0;

            puts(strcmp(str1,str2)==0 ? "YES" : "NO");
            //比较两个遍历字符串,若相同则输出YES,否则输出NO
        }
    }
    return 0;
}

同样也可以选择中序和后序的排序结果共同对两棵树进行判定。但在选择的两种遍历方式中必须要包括中序遍历。如在数据结构中所讲,只有包括中序的两种遍历顺序才能唯一的确定一棵二叉树。

最后对二叉排序树的删除作适当的补充。二叉排序树的删除在机试题中考察的概率非常小。

要删除二叉排序树上的某一个结点,按如下步骤进行:
1.利用某种遍历找到该结点。
2.若该结点为叶子结点,则直接删除它,即将其双亲结点中指向其的指针改为NULL。释放该节点空间。
3.若该结点仅不存在右子树,则直接将其左子树的根结点代替其位置后,删除该结点。即将其双亲结点指向其的指针改为指向其的左子树树根。
4.若该节点存在右子树,则找到右子树上最右下的结点(即中序遍历中该子树上第一个被遍历到的结点),将被删除结点的数值改为右子树上最右下结点的数值后,删除最右下结点。

删除二叉树的原理非常简单,即删除该结点后,其中序遍历依然保持关键字递增的顺序,只要符合这个条件,不同于上述规则的删除也是可行的。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值