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

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值