給定兩棵樹T1和T2。如果T1可以通過若干次左右孩子互換就變成T2,則我們稱兩棵樹是“同構”的。例如圖1給出的兩棵樹就是同構的,因爲我們把其中一棵樹的結點A、B、G的左右孩子互換後,就得到另外一棵樹。而圖2就不是同構的。
圖一
圖二
現給定兩棵樹,請你判斷它們是否是同構的。
輸入格式:
輸入給出2棵二叉樹樹的信息。對於每棵樹,首先在一行中給出一個非負整數N (≤10),即該樹的結點數(此時假設結點從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<stdio.h>
#include<stdlib.h>
#define MAXSIZE 10
#define Null -1
#define ElementType char
#define Tree int
// 結構表示
typedef struct TNode BinTree;
struct TNode{
ElementType data;
Tree left;
Tree right;
} T1[MAXSIZE], T2[MAXSIZE];
Tree createTree(BinTree T[]);
int Isomorphism(Tree R1, Tree R2);
int main(){
Tree R1, R2;
R1 = createTree(T1);
R2 = createTree(T2);
if( Isomorphism(R1, R2) )
printf("Yes\n");
else
printf("No\n");
return 0;
}
// 判斷T1, T2是否同構
int Isomorphism(Tree R1, Tree R2){
// 兩個空樹表示是同構的
if(R1 == Null && R2 == Null)
return 1;
// 一棵樹空另一顆非空,則不同構
if( (R1==Null&&R2!=Null) || (R1!=Null&&R2==Null) )
return 0;
// 兩顆樹非空,但是根節點不一樣,不同構
if(T1[R1].data != T2[R2].data)
return 0;
// 兩顆樹的左子樹空,則比較右子樹就行了
if( T1[R1].left == Null && T2[R2].left == Null)
return Isomorphism(T1[R1].right, T2[R2].right);
// 兩棵樹的左子樹不空並且左子樹的根節點相同, 這樣左子樹和左子樹比較,右子樹和右子樹比較就好
if( (T1[R1].left != Null) && (T2[R2].left != Null) && (T1[T1[R1].left] == T2[T2[R2].left) )
return Isomorphism(T1[R1].left, T1[R1].left) && Isomorphism(T1[R1].right, T1[R1].right);
else // 兩個左子樹的根節點不同,這樣的話就左子樹和右子樹比較,右子樹和左子樹比較
return Isomorphism(T1[R1].left, T1[R1].right) && Isomorphism(T1[R1].left, T1[R1].right);
// 上面的代碼概括了全部的可能,樹空、一顆空一顆不空、都不空時左子樹空,都不空時左子樹不空並且左子樹
// 根節點相同、都不空時左子樹不空但是根節點不同
// 注意:這裏“左子樹根節點”是指將左子樹看成一棵樹時的根節點
}
// 構造二叉樹,返回根節點標號
Tree createTree(BinTree T[]){
Tree root = Null;
int N, i;
int check[MAXSIZE];
// 用來尋找根節點,因爲根節點必定不是任何節點的子樹,所以任何節點的左右子樹的標號不會是根節點標號
// 這樣的話先設置check中元素都爲零,如果那個樹的節點標號在cl或者cr中出現,則設置check中節點標號對應下標
// 爲0,這樣check中唯一爲0的下標就是根節點標號.
char cl, cr;
scanf("%d\n", &N);
if(N > 0){
for(i = 0; i < N; ++i) check[i] = 0;
for(i = 0; i < N; ++i){
scanf("%c %c %c\n", &T[i].data, &cl, &cr);
if(cl != '-'){
T[i].left = cl-'0';
check[T[i].left] = 1;
}else{
T[i].left = Null;
}
if(cr != '-'){
T[i].right = cr-'0';
check[T[i].right] = 1;
}else{
T[i].right = Null;
}
}
for(i = 0; i < N; ++i)
if(!check[i]) break;
root = i;
}
return root;
}