题目来源:
中国大学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
解题思路:
首先审题,讲真我读了一遍题,感觉有思路,然后又看了一遍输入和输出样例,就完全不知道这个题是什么意思了,严重怀疑自己的阅读能力。题目要求我们做的很简单,就是判断按不同的插入序列构成的是否是同一棵二叉搜索树,输入样例中包含好几组输出,每组的第一行的N
和L
分别代表构成树的结点总数,以及需要判断的样例数量,我们把题目给出的输入和输出样例按组划分一下就一目了然了。
第一组输入:
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)); //判断左子树和右子树是否相同
}
如果有哪里理解错的地方欢迎大家留言交流,如需转载请标明出处。
如果你没看懂一定是我讲的不好,欢迎留言,我继续努力。
手工码字码代码,如果有帮助到你的话留个赞吧,谢谢。
以上。