详解-04-树4 是否同一棵二叉搜索树

题目来源:
中国大学MOOC-陈越、何钦铭-数据结构

题目详情:
给定一个插入序列就可以唯一确定一棵二叉搜索树。然而,一棵给定的二叉搜索树却可以由多种不同的插入序列得到。例如分别按照序列{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

解题思路:
首先审题,讲真我读了一遍题,感觉有思路,然后又看了一遍输入和输出样例,就完全不知道这个题是什么意思了,严重怀疑自己的阅读能力。题目要求我们做的很简单,就是判断按不同的插入序列构成的是否是同一棵二叉搜索树,输入样例中包含好几组输出,每组的第一行的NL分别代表构成树的结点总数,以及需要判断的样例数量,我们把题目给出的输入和输出样例按组划分一下就一目了然了。

第一组输入:

4 2 //N和L
3 1 4 2  //初始插入序列
3 4 1 2  //需要检查的插入序列
3 2 4 1  //需要检查的插入序列

第一组输出:

Yes
No

第二组输入:

2 1  //N和L
2 1  //初始插入序列
1 2  //需要检查的插入序列

第二组输出:

No

第三组输入:

0

因为题目要求输入为0的时候表示输入结束,该组数据不处理,因此没有输出。

知道题目让我们干什么之后再来看看如何实现。
由输入输出实例可知,输入是个一直在输入的过程,直到碰到输入的N为0时停止,因此我们考虑用一个循环来捕获输入数据,每次的输入的数据中有1行N个数据为初始插入序列,L行N个为需要检查的插入序列,因此再捕获输入的循环中再加入一个循环用来捕获L行的需要检测序列,每捕获一个需要检测的序列就判断一次是否是相同的二叉搜索树,并将结果输出。

根据以上分析我们得到了程序的整体框架的逻辑如下:

int main(){
	while(1){
	捕获N和L
	if(N){
		for(int i=0; i<N; i++)
			捕获初始插入序列并建树
		for(int i=0; i<L; i++){
			for(int j=0; j<N; j++){
			   逐行捕获需检测插入序列并建树
			}
			判断是否是同一个棵二叉搜索树并输出
		}
	else
		break;
	return 0;
}

因此我们即可按照如上的逻辑来编程,剩下的就是如何建树和如何判断是否是同一棵二叉树,直接看代码就好,关键部分我已经注释。

完整的程序如下:

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

typedef struct TreeNode *Tree;
typedef struct TreeNode{
    int val;
    Tree left;
    Tree right;
}Node;

Tree insert(Tree BST, int val);
int isSameTree(Tree real, Tree temp);

int main(){
    int N, L, val, i, j;
    while(1){
        scanf("%d %d", &N, &L);
        if(!N)
            break;
        else{
            Tree real = NULL, temp = NULL;
            for(i=0; i<N; i++){
                scanf("%d", &val);
                real = insert(real, val);
            }
            for(i=0; i<L; i++){
                temp = NULL;
                for(j=0; j<N; j++){
                    scanf("%d", &val);
                    temp = insert(temp, val);
                }
                if(isSameTree(real, temp))
                    printf("Yes\n");
                else
                    printf("No\n");
            }
        }
    }
    return 0;
}

Tree insert(Tree BST, int val){
    if(!BST){ //若原树为空,生成并返回一个结点的二叉搜索树
        BST = (Tree)malloc(sizeof(Node));
        BST->val = val;
        BST->left = BST->right = NULL;
    }
    else{
        if(val < BST->val)
            BST->left = insert(BST->left, val);   //递归插入左子树
        else if(val > BST->val)
            BST->right = insert(BST->right, val); //递归插入右子树
        //else val已经存在,什么都不做
    }
    return BST;
}

int isSameTree(Tree real, Tree temp){
    if(real == NULL && temp == NULL) //两树皆为空
        return 1;
    if(!(real && temp)) //两树不同时为空
        return 0; 
    if(real->val != temp->val) //两个树结点值不同
        return 0;
    return (isSameTree(real->left, temp->left) && isSameTree(real->right, temp->right)); //判断左子树和右子树是否相同
}

如果有哪里理解错的地方欢迎大家留言交流,如需转载请标明出处。

如果你没看懂一定是我讲的不好,欢迎留言,我继续努力。

手工码字码代码,如果有帮助到你的话留个赞吧,谢谢。

以上。

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值