樹的同構

給定兩棵樹T1和T2。如果T1可以通過若干次左右孩子互換就變成T2,則我們稱兩棵樹是“同構”的。例如圖1給出的兩棵樹就是同構的,因爲我們把其中一棵樹的結點A、B、G的左右孩子互換後,就得到另外一棵樹。而圖2就不是同構的。


圖一


圖二


現給定兩棵樹,請你判斷它們是否是同構的。

輸入格式:

輸入給出2棵二叉樹樹的信息。對於每棵樹,首先在一行中給出一個非負整數N (10),即該樹的結點數(此時假設結點從0到N1編號);隨後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;
}


發佈了42 篇原創文章 · 獲贊 12 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章