一:题目
7-3 树的同构 (25 分)
给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A、B、G的左右孩子互换后,就得到另外一棵树。而图2就不是同构的。
图1
图2
输入格式:
输入给出2棵二叉树树的信息。对于每棵树,首先在一行中给出一个非负整数N (≤),即该树的结点数(此时假设结点从0到N−1编号);随后N行,第i行对应编号第i个结点,给出该结点中存储的1个英文大写字母、其左孩子结点的编号、右孩子结点的编号。如果孩子结点为空,则在相应位置上给出“-”。给出的数据间用一个空格分隔。注意:题目保证每个结点中存储的字母是不同的。
输出格式:
如果两棵树是同构的,输出“Yes”,否则输出“No”。
输入样例1(对应图1):
8
A 1 2
B 3 4
C 5 -
D - -
E 6 -
G 7 -
F - -
H - -
8
G - 4
B 7 6
F - -
A 5 1
H - -
C 0 -
D - -
E 2 -
输出样例1:
Yes
输入样例2(对应图2):
8
B 5 7
F - -
A 0 3
C 6 -
H - -
D - -
G 4 -
E 1 -
8
D 6 -
B 5 -
E - -
H - -
C 0 2
G - 3
F - -
A 1 4
输出样例2:
No
二:具体实现
#include<iostream> #include<cstdlib> using namespace std; typedef struct tree { char c; char c1[2]; int d[2]; tree *lchild,*rchild,*parent; }*node; node* Read(int &n) { node *p; cin>>n; p=new node[n]; //一定要给指针开辟空间 for(int i=0;i<n;i++) { p[i]=new tree; p[i]->lchild=p[i]->rchild=NULL; } for(int i=0;i<n;i++) { cin>>p[i]->c; cin>>p[i]->c1[0]>>p[i]->c1[1]; if(p[i]->c1[0]=='-') p[i]->d[0]=-1; else p[i]->d[0]=(int)p[i]->c1[0]-48; if(p[i]->c1[1]=='-') p[i]->d[1]=-1; else p[i]->d[1]=(int)p[i]->c1[1]-48; } return p; } tree* Creatree(node *p,int n) { for(int i=0;i<n;i++) { if(p[i]->d[0]!=-1) { p[i]->lchild=p[p[i]->d[0]]; p[p[i]->d[0]]->parent=p[i]; } else p[i]->lchild=NULL; if(p[i]->d[1]!=-1) { p[i]->rchild=p[p[i]->d[1]]; p[p[i]->d[1]]->parent=p[i]; } else p[i]->rchild=NULL; } for(int i=0;i<n;i++) { if(p[i]->parent==NULL) return p[i]; } } void Compare(tree *p,tree *p1) { if(p==NULL&&p1==NULL)//laing { cout<<"Yes";exit(0); } else if((p==NULL&&p1!=NULL)||(p!=NULL&&p1==NULL)) { cout<<"No";exit(0); } else { if(p->c!=p1->c) { cout<<"No";exit(0); } else { if(p->lchild!=NULL&&p->rchild!=NULL&&p1->lchild!=NULL&&p1->rchild!=NULL)//两者左右孩子都不为空 { if((p->lchild->c==p1->lchild->c&&p->rchild->c==p1->rchild->c)||(p->lchild->c==p1->rchild->c&&p->rchild->c==p1->lchild->c)) { if(p->lchild->c==p1->lchild->c&&p->rchild->c==p1->rchild->c) {Compare(p->lchild,p1->lchild);Compare(p->rchild,p1->rchild);} else if(p->lchild->c==p1->rchild->c&&p->rchild->c==p1->lchild->c) {Compare(p->lchild,p1->rchild);Compare(p->rchild,p1->lchild);} } else { cout<<"No"; exit(0); } } else if(p->lchild!=NULL&&p->rchild==NULL&&p->lchild!=NULL&&p->rchild==NULL)//两者左孩子都不空,右孩子都空 { if(p->lchild->c!=p1->lchild->c) { cout<<"No"; exit(0); } else Compare(p->lchild,p1->lchild); } else if(p->lchild==NULL&&p->rchild!=NULL&&p->lchild==NULL&&p->rchild!=NULL)//两者右孩子都不空,左孩子都空 { if(p->rchild->c!=p1->rchild->c) { cout<<"No"; exit(0); } else Compare(p->rchild,p1->rchild); } else if(p->lchild!=NULL&&p->rchild==NULL&&p->lchild==NULL&&p->rchild!=NULL)//前者左孩子不空,后者右孩子不空 { if(p->lchild->c!=p1->rchild->c) { cout<<"No"; exit(0); } else Compare(p->lchild,p1->rchild); } else if(p->lchild==NULL&&p->rchild!=NULL&&p->lchild!=NULL&&p->rchild==NULL)//前者右孩子不空,后者左孩子不空 { if(p->rchild->c!=p1->lchild->c) { cout<<"No"; exit(0); } else Compare(p->rchild,p1->lchild); } else if(p->lchild==NULL&&p->rchild==NULL&&p->lchild==NULL&&p->rchild==NULL)//两者都没有孩子 {} else { cout<<"No"; exit(0); } } } cout<<"Yes"; exit(0); } int main() { node *p,*p1; tree *q,*q1; /* 声明指针不会创建用于存储的内存空间。 指针声明时,指向的位置不确定,程序运行时,如果你运气好可能不出错,但是下次动态分配内存的时候你可能就没这么幸运了。 例子 int *a; *a=12; 这是一个典型的错误:因为在分配内存时你无法确定 a 指向的位置,所以你下次 *a或者访问a时, 可能带来:Program received signal SIGSEGV, Segmentation fault.*/ q=new tree; q1=new tree; p=new node; p1=new node; int n=0; p=Read(n); q=Creatree(p,n); p1=Read(n); q1=Creatree(p1,n); Compare(q,q1); }
三:总结
1.定义二级指针后,一定不要忘了给二级指针初始化!
2.定义指针后一定要给其开辟空间,不然很可能会出错。如:
1.声明指针不会创建用于存储的内存空间。
2.指针声明时,指向的位置不确定,程序运行时,如果你运气好可能不出错,但是下次动态分配内存的时候你可能就没这么幸运了。
例子:
int *a; *a=12;
这是一个典型的错误:因为在分配内存时你无法确定 a 指向的位置,所以你下次 *a或者访问a时, 可能带来:Program received signal SIGSEGV, Segmentation fault.(调试出现的错误)