04-树4 是否同一棵二叉搜索树 (25 分)

本文介绍了一种算法,用于判断多个插入序列是否能够生成相同的二叉搜索树。通过构建二叉搜索树并比较不同序列生成的树是否一致,解决了一个计算机科学中的经典问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给定一个插入序列就可以唯一确定一棵二叉搜索树。然而,一棵给定的二叉搜索树却可以由多种不同的插入序列得到。例如分别按照序列{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
#include <stdio.h>
#include <stdlib.h>
typedef struct TreeNode *Tree;
struct TreeNode {
	int v;	//结点大小。
	Tree Left, Right;	 
	int flag;	//访问过标记1,否则标记0。
};

Tree MakeTree( int N );
Tree NewNode ( int V );
Tree Insert( Tree T, int V );
int check ( Tree T, int V );
int Judge( Tree T, int N );
void ResetT (Tree T);
void FreeTree( Tree T );

int main(void) {
	int N, L, i;
	Tree T;
	
	scanf("%d", &N);	//搜索树的结点个数。
	while ( N ) {
		scanf("%d", &L);	//待比较的序列行数。
		T = MakeTree(N);	//建树。
		for ( i = 0; i < L; i++ ) {	//将L行序列跟T比较。
			if ( Judge( T,N ) )	printf("Yes\n");
			else	printf("No\n");
			ResetT( T );	//清除T中的flag。
		}
		FreeTree( T );	//一组数据处理完毕,释放T的空间。
		scanf("%d", &N);	//读入下一组数据。
	}
	 
	return 0;
}

Tree MakeTree( int N ) {
	Tree T;
	int i, V;
	
	scanf("%d", &V);	//读入根结点信息。
	T = NewNode( V );	//为根结点申请新的空间。
	for ( i = 1; i < N; i++ ) {	//将后面N-1个数插入到T中。
		scanf("%d", &V);
		T = Insert( T, V );	
	} 
	
	return T;
}

Tree NewNode ( int V ) {
	Tree T = (Tree)malloc(sizeof(struct TreeNode));
	T->v = V;
	T->Left = T->Right = NULL;
	T->flag = 0;
	return T;
}

Tree Insert( Tree T, int V ) {
	if ( !T )	T = NewNode(V);	//空树情况,需要新建结点。
	else { 
		if ( V > T->v )
			T->Right = Insert( T->Right, V );
		else
			T->Left = Insert( T->Left, V );
	}
	return T;
}

int check ( Tree T, int V ) {
	if ( T->flag ) {	//若根结点的flag是1,说明被访问过。
		if ( V < T->v )	return check ( T->Left, V );
		else if( V > T->v )	return check ( T->Right, V );
		else	return 0;	//如果同一结点出现2次,必定不一致。
	}
	else {	//flag为0,说明没被访问过。
		if ( V == T->v ) {	//当前结点和待查结点一致标记为1.
			T->flag = 1;
			return 1;
		}
		else	return 0;	//若碰到了一个以前没有见过的结点,那肯定不一致。
	}
}

int Judge( Tree T, int N ) {
	int i, V, flag = 0;	//flag = 0代表目前还一致,1代表已经不一致。
	
	scanf("%d", &V);
	if ( V != T->v )	flag = 1;	//树根不同,必然不一致。
	else	T->flag = 1;	
	
	for ( i = 1; i < N; i++ ) {	//对后面N-1个数进行check().
		scanf("%d", &V);
		if ( (!flag) && (!check(T, V)) )	flag = 1;
	}
	if ( flag )	return 0;
	else return 1;
}

void ResetT (Tree T) {	
	if ( T->Left )	ResetT( T->Left );
	if ( T->Right )	ResetT( T->Right );
	T->flag = 0;
} 

void FreeTree( Tree T ) {	
	if ( T->Left )	FreeTree( T->Left );
	if ( T->Right )	FreeTree( T->Right );
	free(T);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值