二叉樹同構


樹的同構:     

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

 


 

圖1

圖2

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

 

輸入格式:

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

本題使用結構數組(靜態鏈表)存儲二叉樹
結構定義:
#define MaxTree 10
#define ElementType char
#define Tree int
#define Null -1

struct TreeNode
{
    ElementType Element;
    Tree Left;
    Tree Right;
}T1[MaxTree], T2[MaxTree];

每個結點包含一個值和左右節點在數組中的位置

 

程序整體結構:

1、根據輸入,構建二叉樹

int BuildTree(struct TreeNode T[])
{
    int N, i, root = Null;
    char cl, cr;
    scanf("%d", &N);
    if(N){
        int check[MaxTree];//用於判斷根節點
        for(i = 0; i < N; i++){
            check[i] = 0;
        }


        for (i = 0; i < N; i++){    
            getchar();
            scanf("%c %c %c", &T[i].Element, &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 (0 == check[i]){
                root = i;
                break;
            }
        }
    }
    return root;
}

 

要注意的是,要將換行過濾,避免存入結構數組里

getchar();
scanf("%c %c %c", &T[i].Element, &cl, &cr);

如何判斷根節點?

未被指向過的節點就是根節點(節點存在,但對應的數組下標從未出現在其他節點的Left和Right

對應程序,使用check數組變量:
1、數組長度和節點個數一樣,初始化為0
2、一旦某個節點有指向信息,chenck數組對應下標處置1

輸入全部處理完成后,依然保持0的就是從未被指向過的節點,就是想要的根節點


2、判斷二叉樹同構:
int Isomorphic(Tree R1, Tree R2)
{
    if ((R1 == Null) && (R2 == Null)){
        return 1;
    }

    //對應一個樹存在某個節點,而另一個樹沒有該節點
    else if ((R1 == Null && R2 != Null) || (R2 == Null && R1 != Null)){
        return 0;
    }

    else if (T1[R1].Element != T2[R2].Element)
    {
        return 0;
    }

    else if (Isomorphic(T1[R1].Left, T2[R2].Left) && Isomorphic(T1[R1].Right, T2[R2].Right)) {
        return 1;
    }
    else if (Isomorphic(T1[R1].Left, T2[R2].Right) && Isomorphic(T1[R1].Right, T2[R2].Left)){
        return 1;
    }

    return  0;
}

邏輯判斷要從大處着眼

只要R1和R2不為空,就去判斷它們的左右子樹是否同構,不需要多此一舉的判斷R1、R2的左又子節點是否為空,(子節點是否為空自然會在下一次遞歸調用中判斷),遞歸要做到只關心當次循環


完整程序:
  1 #include<iostream>
  2 using std::cout;
  3 using std::endl;
  4 
  5 #define MaxTree 10
  6 #define ElementType char
  7 #define Tree int
  8 #define Null -1
  9 
 10 struct TreeNode
 11 {
 12     ElementType Element;
 13     Tree Left;
 14     Tree Right;
 15 }T1[MaxTree], T2[MaxTree];
 16 
 17 /*
 18 8
 19 A 1 2
 20 B 3 4
 21 C 5 -
 22 D - -
 23 E 6 -
 24 G 7 -
 25 F - -
 26 H - -
 27 8
 28 G - 4
 29 B 7 6
 30 F - -
 31 A 5 1
 32 H - -
 33 C 0 -
 34 D - -
 35 E 2 -
 36 */
 37 
 38 
 39 int BuildTree(struct TreeNode T[])
 40 {
 41     int N, i, root = Null;
 42     char cl, cr;
 43     scanf("%d", &N);
 44     if(N){
 45         int check[MaxTree];//用於判斷根節點
 46         for(i = 0; i < N; i++){
 47             check[i] = 0;
 48         }
 49 
 50 
 51         for (i = 0; i < N; i++){    
 52             getchar();
 53             scanf("%c %c %c", &T[i].Element, &cl, &cr);
 54             if (cl != '-'){
 55                 T[i].Left = cl - '0';
 56                 check[T[i].Left] = 1;
 57             }else{
 58                 T[i].Left = Null;
 59             }
 60 
 61             if (cr != '-'){
 62                 T[i].Right = cr - '0';
 63                 check[T[i].Right] = 1;
 64             }
 65             else{
 66                 T[i].Right = Null;
 67             }
 68         }
 69 
 70 
 71         for (i = 0; i < N; i++){
 72             if (0 == check[i]){
 73                 root = i;
 74                 break;
 75             }
 76         }
 77     }
 78     return root;
 79 }
 80 
 81 
 82 int Isomorphic(Tree R1, Tree R2)
 83 {
 84     if ((R1 == Null) && (R2 == Null)){
 85         return 1;
 86     }
 87 
 88     //對應一個樹存在某個節點,而另一個樹沒有該節點
 89     else if ((R1 == Null && R2 != Null) || (R2 == Null && R1 != Null)){
 90         return 0;
 91     }
 92 
 93     else if (T1[R1].Element != T2[R2].Element)
 94     {
 95         return 0;
 96     }
 97 
 98     else if (Isomorphic(T1[R1].Left, T2[R2].Left) && Isomorphic(T1[R1].Right, T2[R2].Right)) {
 99         return 1;
100     }
101     else if (Isomorphic(T1[R1].Left, T2[R2].Right) && Isomorphic(T1[R1].Right, T2[R2].Left)){
102         return 1;
103     }
104 
105     return  0;
106 }
107 
108 int main()
109 {
110     freopen("data.txt", "r", stdin);//輸入重定向,方便調試
111     Tree r1, r2;
112 
113     r1 = BuildTree(T1);
114     r2 = BuildTree(T2);
115     if (Isomorphic(r1, r2)){
116         cout<< "Yes"<<endl ;
117     }
118     else
119     {
120         cout << "No" << endl;
121     }
122 
123     return 0;
124 }
View Code

 






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM