7-1 是否同一棵二叉搜索树 (34 分)
给定一个插入序列就可以唯一确定一棵二叉搜索树。然而,一棵给定的二叉搜索树却可以由多种不同的插入序列得到。例如分别按照序列{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 shu {
int *shu;
int *maxshu;
int *minshu;
int max;
int min;
} S;
S *creat(int N);
void justify(S *head, S *tran );
int main() {
int N,L;
scanf("%d",&N);
while(N!=0) {
scanf("%d",&L);
S *head;
head=creat(N);
for(int i=0; i<L; i++) {
S *tran;
tran=creat(N);
justify(head,tran);
}
scanf("%d",&N);
}
}
S *creat(int N) {
S *head;
head=(S*)malloc(sizeof(S));
head->shu=(int *)malloc(sizeof(int)*N);
head->maxshu=(int *)malloc(sizeof(int)*N);
head->minshu=(int *)malloc(sizeof(int )*N);
head->max=head->min=0;
//输入且分组
for(int i=0; i<N; i++) {
scanf("%d",&head->shu[i]);
if(i!=0) {
if(head->shu[i]>head->shu[0]) {
head->maxshu[head->max]=head->shu[i];
head->max++;
} else {
head->minshu[head->min]=head->shu[i];
head->min++;
}
}
}
int k=head->min;
for(int i=0; i<head->max; i++) {
head->minshu[k]=head->maxshu[i];
k++;
}
for(int i=0;i<head->min+head->max;i++){
printf("%d\n",head->minshu[i]);
}
return head;
}
void justify(S *head, S *tran ) {
int flag=1;
if(tran->shu[0]==head->shu[0]) {
if(tran->min==head->min&&tran->max==head->max) {
for(int j=0; j<(head->min+head->max); j++) {
if(head->minshu[j]!=tran->minshu[j]) {
printf("No\n");
flag=0;
break;
}
}
if(flag==1) {
printf("Yes\n");
}
} else {
printf("No\n");
}
} else {
printf("No\n");
}
}
/*
10 1
5 1 8 0 4 6 9 2 7 10 3
5 8 1 9 4 0 6 7 10 2 3
*/
方法二:
采用都建立树的方法然后采用某一输出方式用数组进行存储然后进行判断。
#include <stdio.h>
#include <stdlib.h>
typedef struct shu {
int data;
struct shu *left,*right;
} S;
S *creat(S *head,int x);
void Printf(S *head,int *a );
int sum=0;
int main() {
int N,L,x;
scanf("%d",&N);
while(N!=0) {
int a[N],b[N],flag=0;
scanf("%d",&L);
S *head;
head=NULL;
for(int i=0; i<N; i++) {
scanf("%d",&x);
head=creat(head,x);
}
//存入数组
sum=0;
Printf(head,a);
//比较几次
for(int j=0; j<L; j++) {
int flag1=1;
flag=0;
S *tran;
tran=NULL;
for(int i=0; i<N; i++) {
scanf("%d",&x);
tran=creat(tran,x);
}
sum=0;
Printf(tran,b);
for(int k=0; k<N; k++) {
if(a[k]!=b[k]) {
printf("No\n");
flag1=0;
break;
}
}
if(flag1==1)
printf("Yes\n");
}
scanf("%d",&N);
}
}
//建立二插排序树,即用插入的方法。:要不断的返回
S *creat(S *head,int x) {
if(!head) {
head=(S*)malloc(sizeof(S));
head->data=x;
head->left=head->right=NULL;
} else {
if(x>head->data)
head->right=creat(head->right,x);
else if(x<head->data)
head->left=creat(head->left,x);
}
return head;
}
//存入数组
void Printf(S *head,int *a ) {
if(head) {
a[sum++]=head->data;
Printf(head->left,a);
Printf(head->right,a);
}
}
方法三:只建立一棵树,另一个要进行比较的树一个一个的和建立的数进行比较。
#include <stdio.h>
#include <stdlib.h>
typedef struct shu {
int data;
struct shu *left,*right;
int flag;
} tree;
int finashu(tree *head,int N);
tree *creatshu(tree *head,int N);
tree *intshu(tree *head,int x);
void Freeshu(tree *head);
void PRINTF(tree *head);
int main() {
int N,L;
scanf("%d",&N);
while(N) {
scanf("%d",&L);
tree *head;
head=NULL;
head=creatshu(head,N);
// PRINTF(head);
for(int i=0; i<L; i++) {
int x=finashu(head,N);
if(x)
printf("Yes\n");
else
printf("No\n");
Freeshu(head);//清楚flag进行下一次的判断
}
scanf("%d",&N);
free(head);
}
return 0;
}
tree *creatshu(tree *head,int N) {
int x;
for(int i=0; i<N; i++) {
scanf("%d",&x);
head=intshu(head,x);
}
return head;
}
tree *intshu(tree *head,int x) {
if(!head) {
head=(tree*)malloc(sizeof(tree));
head->data=x;
head->left=head->right=NULL;
head->flag=0;
} else {
if(x>head->data)
head->right=intshu(head->right,x);
else
head->left=intshu(head->left,x);
}
return head;
}
//关键操作进行查找
int finashu(tree *head,int N) {
int a[N];
for(int i=0; i<N; i++)
scanf("%d",&a[i]);
/*for(int i=0;i<N;i++){
printf("数组的:%d\n",a[i]);
}*/
//查找的关键点:在不等于的时候判断flag是否为1,如果不为1则就是不同的树。
//如果flag=1,且不相等则去下一个数。
//如果相等直接将flag=1即可
//二插排序树的查找
//这一段的错误,除了保证移动数组还要保证每次进行比较时head从头开始。
tree *tran=head;
for(int i=0; i<N;) {
// printf("%d and %d\n",a[i],head->data);
if(a[i]==head->data) {
head->flag=1;
head=tran;
i++;
} else {
if(a[i]>head->data) {
if(head->flag==1) {
head=head->right;
continue;
} else if(head->flag!=1) {
return 0;
}
} else {
if(head->flag==1) {
head=head->left;
continue;
} else if(head->flag!=1) {
return 0;
}
}
}
}
return 1;
}
//清除标记:用先序遍历的方式进行清除
void Freeshu(tree *head) {
if(head) {
head->flag=0;
Freeshu(head->left);
Freeshu(head->right);
}
}
void PRINTF(tree *head) {
if(head) {
printf("head:%d",head->data);
PRINTF(head->left);
PRINTF(head->right);
}
}
/*
7 1
7 5 8 1 6 9 10
7 8 5 9 1 6 10
*/