题目:
给定一个插入序列就可以唯一确定一棵二叉搜索树。然而,一棵给定的二叉搜索树却可以由多种不同的插入序列得到。例如分别按照序列{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
算法
不建树
每次通过第一个结点将序列分为左子树和右子树(左、右子树中元素的原始相对顺序不能改变),然后递归左子树和右子树
代码实现
int main()
{
int N,L;
scanf("%d",&N);
while(N!=0){
int i,j;
scanf("%d",&L);
//构造参照标准
int* S=(int*)malloc(sizeof(int)*N);
{
for(i=0;i<N;i++){
scanf("%d",&S[i]);
}
}
for(i=0;i<L;i++){
//读入代比对序列
int* A=(int*)malloc(sizeof(int)*N);
{
for(j=0;j<N;j++){
scanf("%d",&A[j]);
}
}
//比对
int result=1;
result=Compare(S,A,N);
//输出结果
if(result==0){
printf("No\n");
}else{
printf("Yes\n");
}
free(A);
}
scanf("%d",&N);
}
return 0;
}
Compare函数:由于参考数据S要多次用到,所以在这里复制一份传入递归函数Recursion
int Compare(int S[],int A[],int n)
{
int* B=(int*)malloc(sizeof(int)*n);
int i=0;
for(i=0;i<n;i++){
B[i]=S[i];
}
int ret;
ret=Recursion(B,A,n);
free(B);
return ret;
}
Recursion函数:
//将S和A数组分别根据第一个元素分为左序列和右序列
从第二个元素开始,如果其小于首元素,i 指针直接后移;如果大于第一个元素,j 指针向后找到后续元素中第一个小于首元素的元素,然后将当前位置到 j 指针的元素都向后推移,然后将 j 指针所指元素填充到当前位置
//检查当前排好序的两个数组是否相同,相同时直接返回;否则进行下一步
//进行左右序列递归
void Swop(int*a,int*b)
{
int c=*a;
*a=*b;
*b=c;
}
int Recursion(int S[],int A[],int n)
{
if(n==0){
return 1;
}
if(n==1){
if(S[0]==A[0]){
return 1;
}else{
return 0;
}
}
if(n==2){
if(S[0]==A[0]&&S[1]==A[1]){
return 1;
}else{
return 0;
}
}
int i,j;
int count=0;
if(S[0]==A[0]){
for(i=1;i<n;i++){
if(S[i]<S[0]){
count++;
}else{
for(j=i+1;j<n;j++){
if(S[j]<S[0]){
int temp=S[j];
int k;
for(k=j;k>i;k--){
S[k]=S[k-1];
};
S[i]=temp;
count++;
break;
}
}
}
if(A[i]>A[0]){
for(j=i+1;j<n;j++){
if(A[j]<A[0]){
int temp=A[j];
int k;
for(k=j;k>i;k--){
A[k]=A[k-1];
};
A[i]=temp;
break;
}
}
}
}
}else{
return 0;
}
int flag=1;
for(i=1;i<n;i++){
if(A[i]!=S[i]){
flag=0;
}
}
if(flag==1)return 1;
return (Recusive(S+1,A+1,count)&&Recusive(S+count+1,A+count+1,n-(count+1)));
}
建两棵树
根据两个序列建两棵树,对比树中的每个结点
代码实现
int main()
{
int n,l;
scanf("%d",&n);
BinTree standard=(BinTree)malloc(sizeof(struct M));
while(n){
scanf("%d",&l);
Initialize(standard,n);
Create(standard);
int j;
int i;
BinTree b=(BinTree)malloc(sizeof(struct M));
for(j=0;j<l;j++){
int flag=1;
//创建测试树
Initialize(b,n);
Create(b);
//测试
for(i=0;i<n;i++){
int Data=standard->M[i].Data;
int j;
for(j=0;j<n&&Data!=b->M[j].Data;j++);
if(j==n||standard->M[standard->M[i].Left].Data!=b->M[b->M[j].Left].Data||standard->M[standard->M[i].Right].Data!=b->M[b->M[j].Right].Data){
flag=0;
break;
}
}
if(flag){
printf("Yes\n");
}else{
printf("No\n");
}
}
free(b);
scanf("%d",&n);
}
free(standard);
return 0;
}
数组存储的二叉搜索树操作
#define MAXSIZE 10
typedef struct Table{
int Data;
int Left;
int Right;
}Matrix[MAXSIZE];
typedef struct M{
int Size;
Matrix M;
}*BinTree;
void Create(BinTree a)
{
int i;
for(i=0;i<a->Size;i++){
int t=0;
scanf("%d",&t);
a->M[i].Data=t;
Instert(a,t,i);
}
}
void Instert(BinTree standard,int t ,int num)
{
int i=0;
while(1){
if(t<standard->M[i].Data){
if(standard->M[i].Left==0){
standard->M[i].Left=num;
break;
}else{
i=standard->M[i].Left;
}
}else{
if(standard->M[i].Right==0){
standard->M[i].Right=num;
break;
}else{
i=standard->M[i].Right;
}
}
}
}
void Initialize(BinTree A,int n)
{
int i;
A->Size=n;
for(i=0;i<MAXSIZE;i++){
A->M[i].Data=0;
A->M[i].Left=0;
A->M[i].Right=0;
}
}
建一棵树
代码实现
二叉搜索树的构造
链表存储的二叉搜索树
typedef struct TreeNode* Tree;
struct TreeNode{
int Data;
Tree Left;
Tree Right;
int Flag;
};
Tree CreateNode(int V)
{
Tree T=(Tree)malloc(sizeof(struct TreeNode));
T->Data=V;
T->Left=NULL;
T->Right=NULL;
T->Flag=0;
return T;
}
Tree Insert(Tree T,int V)
{
if(!T)T=CreateNode(V);
if(T->Data>V){
T->Left=Insert(T->Left,V);
}else if(T->Data<V){
T->Right=Insert(T->Right,V);
}
return T;
}
Tree MakeTree(int n)
{
int Temp;
scanf("%d",&Temp);
Tree T=CreateNode(Temp);
int i;
for(i=1;i<n;i++){
scanf("%d",&Temp);
T=Insert(T,Temp);
}
return T;
}
/*树结点空间释放函数*/
void FreeTree(Tree T)
{
if(T->Left){
FreeTree(T->Left);
}
if(T->Right){
FreeTree(T->Right);
}
free(T);
}
整体框架
int main()
{
int n,l,j;
Tree T;
scanf("%d",&n);
while(n){
scanf("%d",&l);
T=MakeTree(n);
for(j=0;j<l;j++){
int flag=Judge(T,n);
if(flag){
printf("Yes\n");
}else{
printf("No\n");
}
Reset(T);
}
FreeTree(T);
scanf("%d",&n);
}
return 0;
}
核心处理函数
/*从根节点开始向下查找V是否在树中,同时检查路径中结点是否在先前已经访问过*/
int Check(Tree T,int V)
{
if(T->Data==V){
T->Flag=1;
return 1;
}
if(T->Data>V&&T->Flag==1){
return Check(T->Left,V);
}else if(T->Data<V&&T->Flag==1){
return Check(T->Right,V);
}else{
return 0;
}
}
/*待检查序列逐项输入,当发现某一项在树中的位置不正确时,触发标记 flag,后续逐项继续输入,但不再调用Check函数*/
int Judge(Tree T,int n)
{
int V,i;
int flag=1;
for(i=0;i<n;i++){
scanf("%d",&V);
if(flag==1){
flag=Check(T,V);
}
}
return flag;
}
/*每次检查完一个序列,清洗搜索树中结点的标记位*/
void Reset(Tree T)
{
if(T->Flag==1){
T->Flag=0;
}
if(T->Left){
Reset(T->Left);
}
if(T->Right){
Reset(T->Right);
}
}