给定一个插入序列就可以唯一确定一棵二叉搜索树。然而,一棵给定的二叉搜索树却可以由多种不同的插入序列得到。例如分别按照序列{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
小结:
这道题还是比较简单的,主要练习栽树,遍历等基本操作;基础很重要,复杂的问题都是一步步转化为简单的问题,从而逐步攻克;多看老师和大神们写代码的思路,多有裨益,诸君共勉
这是听老师解答前自己写的AC代码(C语言)
/*
基本思路:
1.根据每一组序列
栽对应的二叉搜索树
2.遍历每棵树,结果存入数组中,对比两个数组,有一个 同一个位置存在不同的数 就表示是不同的树
由于最大个数MaxSize == 10,所以将树转为数组后,占用空间不是大,这个思路还是可取的,
但是如果数据过多,将导致数组过大,这个思路就不行了 */
#include <stdio.h>
#include <stdlib.h>
typedef struct _BSTNode BST;
struct _BSTNode{
int Data;
BST* Left;
BST* Right;
};
void CreatBST( BST* *p,int N );//栽树函数
void TreeToArray( BST* Tree,int* Array,int N );//将树中的数据存储在数组中
void FreeTree( BST* Tree );//释放动态内存
int main()
{
int N,L;
scanf("%d",&N);
BST *ReferenceBST,*ControlBST; //参照树 和 对照树
int Reference[N],Control[N]; //层序遍历后对应的数组
while(N){
scanf("%d",&L);
/*个人习惯 传树的地址进去,这样可以不用函数返回值;
也可以利用函数返回值栽树ReferenceBST = CreatBST(N)*/
CreatBST( &ReferenceBST,N );
TreeToArray( ReferenceBST,Reference,N );
while(L--){
CreatBST( &ControlBST,N );
TreeToArray( ControlBST,Control,N );
FreeTree( ControlBST );
int i;
for(i=0;i<N;i++){
if(Reference[i] != Control[i]){
break;
}
}
if(i==N){
printf("Yes\n");
}else{
printf("No\n");
}
}
scanf("%d",&N);
}
FreeTree( ReferenceBST );
return 0;
}
void CreatBST( BST* *p,int N )
{
*p = NULL;//初始化为空树,p表示树的地址
int X;
BST* Temp;//临时指针
while(N--){
scanf("%d",&X);
BST* newTree = (BST*)malloc(sizeof(BST));//新结点
newTree->Data = X;
newTree->Left = newTree->Right = NULL;
Temp = *p;
if(!Temp){
*p = newTree;//如果为空树,则新结点为根结点
}else{
while(Temp){ //迭代的方式将新结点插入对应的位置,老师用的是递归
if(X > Temp->Data){
if(!(Temp->Right)){
Temp->Right = newTree;
Temp = NULL;
}else{
Temp = Temp->Right;
}
}else if(X < Temp->Data){
if(!(Temp->Left)){
Temp->Left = newTree;
Temp = NULL;
}else{
Temp = Temp->Left;
}
}
}
}
}
}
void TreeToArray( BST* Tree,int* Array,int N )
{
BST* Queue[N]; //用于层序遍历的队列
int front,rear,i;
front = rear = -1;//队列的头和尾
i=0; //数组下标
rear++;
Queue[rear] = Tree; //根结点入队列
while(front != rear){
front++; //出队列,将树中数据存储到数组中
Array[i] = Queue[front]->Data;
i++;
if(Queue[front]->Left){ //左儿子入队列
rear++;
Queue[rear] = Queue[front]->Left;
}
if(Queue[front]->Right){ //右儿子入队列
rear++;
Queue[rear] = Queue[front]->Right;
}
}
}
void FreeTree( BST* Tree )
{
if(Tree->Left){
FreeTree(Tree->Left);
}
if(Tree->Right){
FreeTree(Tree->Right);
}
free(Tree);
}
这是听了老师解答后,按照老师的思路写的
/*
老师的方法:只栽一个参照树,
结构中增加一个值flag 用于判断后面给出的序列是否是同一棵树
*/
#include <stdio.h>
#include <stdlib.h>
typedef struct _TreeNode Tree;
struct _TreeNode{
int Data;
Tree* Left;
Tree* Right;
int flag; //0 没有被访问过;1 有被访问过
};
Tree* MakeTree( int N );//栽树函数
int Judge( Tree* BST,int N );//判断函数
int check( Tree* BST,int V );//检查序列中每一个值V 是否和树中的V值 在树中处于同一个位置
void Reset( Tree* BST );//重置树中的flag,以便下次判断
void FreeTree( Tree* BST );//释放malloc的动态内存
int main()
{
int N,L,i;
Tree* BST;
scanf("%d",&N);
while(N){
scanf("%d",&L);
BST = MakeTree(N);
for(i=0;i<L;i++){
if(Judge( BST,N )){
printf("Yes\n");
}else{
printf("No\n");
}
Reset( BST ); //重置BST中的标记flag;
}
FreeTree( BST );
scanf("%d",&N);
}
return 0;
}
Tree* MakeTree( int N )
{
Tree *Temp,
*BST = NULL;
int i,V;
while(N--){
scanf("%d",&V);
Temp = BST;
Tree* newNode = (Tree*)malloc(sizeof(Tree));
newNode->Data = V;
newNode->Left = newNode->Right = NULL;
newNode->flag = 0;
if(!Temp){
BST = newNode;
}else{
while(Temp){
if(V>Temp->Data){
if(Temp->Right){
Temp = Temp->Right;
}else{
Temp->Right = newNode;
Temp = NULL;
}
}else{
if(Temp->Left){
Temp = Temp->Left;
}else{
Temp->Left = newNode;
Temp = NULL;
}
}
}
}
}
return BST;
}
int Judge( Tree* BST,int N )
{
int sign=1, //1 表示目前还一致,0 表示不一致;
i,V;
scanf("%d",&V);
if(V != BST->Data ){
sign = 0;
}else{
BST->flag = 1;
}
for(i=1;i<N;i++){
scanf("%d",&V);
if( (sign) && (!check( BST,V )) ){
sign = 0;
}
}
return sign;
}
int check( Tree* BST,int V )
{
int ret = 1; //1 表示被检查的序列中的V与BST中的V一致,0表示不一致
/*在 找到树中V值的路径 中 如果有 没有经过的结点即->flag==0;
则不是同一棵树,返回0 */
if(BST->flag){
if(V < BST->Data ){
ret = check( BST->Left,V );
}else if(V >BST->Data){
ret = check( BST->Right,V);
}else{
ret = 0;
}
}else{
if(V == BST->Data){
BST->flag = 1;
}else{
ret = 0;
}
}
return ret;//个人喜欢单一出口,老师的函数中有多个出口,所以稍微改了一点点
}
void Reset( Tree* BST )
{
if(BST->Left){
Reset( BST->Left );
}
if(BST->Right){
Reset( BST->Right );
}
BST->flag = 0;
}
void FreeTree( Tree* BST )
{
if(BST->Left){
FreeTree( BST->Left );
}
if(BST->Right){
FreeTree( BST->Right );
}
free(BST);
}