1. 程式人生 > >樹的同構 (25 分)(答案超詳解)第六章樹和二叉樹--樹和森林-計算機17級 7-1

樹的同構 (25 分)(答案超詳解)第六章樹和二叉樹--樹和森林-計算機17級 7-1

7-1 樹的同構 (25 分)

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

圖1

圖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

作者: 陳越

單位: 浙江大學

時間限制: 400 ms

記憶體限制: 64 MB

程式碼長度限制: 16 KB

求解思路:

1.二叉樹表示

2.建立二叉樹 

3.同構判別

程式大致框架

一.二叉樹表示

物理上結構陣列,思想上鍊表------靜態連結串列(具有連結串列的靈活性)

從上圖可以看出靜態連結串列具有連結串列的靈活性,但儲存上則為陣列

注意這裡的left和right不是指標,而是遊標。所以當他們都指向空的時候,NULL可不是0,而是-1(c++規定空指標=0.而為了區分這裡把NULL設為-1)

此外這種表示可以找到樹的根,方法為:遍歷他的下標,最終沒出現的那個就是根

二.建立二叉樹

 建立的難點就是找到樹根,上個問題已經知道了找樹根的方法:把結構陣列從頭到尾掃描一遍,找找有沒有哪個結點不存在其他結點指向它,如果發現有這樣的結點,那他就是樹根。因為非根結點肯定有人指向它

這裡用一個check陣列實現即可

具體實現如下:

Tree BuildTree(struct TNode T[])
{
    int i,n;
    char cl,cr;//左孩子和右孩子
    Tree Root = NULL;//一定記得初始化,因為樹空時還要返回Root(否則就會段錯誤!!!)
    int check[MaxTree] = {0};
    scanf("%d\n",&n);
    if(n)
    {
        for(int i = 0; i < n; i++)
            check[i] = 0;
        for(int i = 0; i < n; i++)
        {
            scanf("%c %c %c\n",&T[i].Element,&cl,&cr);//為了統一,所以都暫時把輸入資料當成char
            //cout<<0;
            //是-說明沒有兒子,所以賦值為NULL
            //不是-說明有兒子,則把對應的值賦值給兒子,並把他的check陣列下標設為1
            if(cl != '-')
            {
                T[i].left = cl - '0';//因為肯定是整數,二剛開始把他們當成字元了,所以要減去'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])//還是0的說明就是根
                break;
        Root = i;
    }
    return Root;
}

三.同構判別

需要考慮很多情況,詳細見程式碼

bool Isomorphic(Tree R1,Tree R2)
{
    if((R1 == NULL)&&(R2==NULL))//兩邊都空
        return true;
    if(((R1 == NULL)&&(R2 != NULL))||((R2 == NULL)&&(R1 != NULL)))//一邊空一邊不空
        return false;
    if(T1[R1].Element != T2[R2].Element)//兩個樹的根不同
        return false;
    if((T1[R1].left==NULL)&&(T2[R2].left==NULL))//兩邊都沒有左子樹
        return Isomorphic(T1[R1].right,T2[R2].right);
    if(((T1[R1].left != NULL)&&T2[R2].left != NULL)&&((T1[T1[R1].left].Element == T2[T2[R2].left].Element)))//不需要交換左邊和右邊
        return (Isomorphic(T1[R1].left,T2[R2].left)&&Isomorphic(T1[R1].right,T2[R2].right));
    else//需要交換左邊和右邊
        return (Isomorphic(T1[R1].left,T2[R2].right)&&Isomorphic(T1[R1].right,T2[R2].left));
}

本題完整實現程式碼:

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
#define MaxTree 10
#define NULL -1//因為這是個靜態連結串列,NULL為-1
typedef char TElemType;
typedef int Tree;
//結構陣列表示1二叉樹:靜態連結串列
struct TNode
{
    TElemType Element;
    Tree left;
    Tree right;
} T1[MaxTree],T2[MaxTree];

Tree BuildTree(struct TNode T[])
{
    int i,n;
    char cl,cr;//左孩子和右孩子
    Tree Root = NULL;//一定記得初始化,因為樹空時還要返回Root
    int check[MaxTree] = {0};
    scanf("%d\n",&n);
    if(n)
    {
        for(int i = 0; i < n; i++)
            check[i] = 0;
        for(int i = 0; i < n; i++)
        {
            scanf("%c %c %c\n",&T[i].Element,&cl,&cr);//為了統一,所以都暫時把輸入資料當成char
            //cout<<0;
            //是-說明沒有兒子,所以賦值為NULL
            //不是-說明有兒子,則把對應的值賦值給兒子,並把他的check陣列下標設為1
            if(cl != '-')
            {
                T[i].left = cl - '0';//因為肯定是整數,二剛開始把他們當成字元了,所以要減去'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])//還是0的說明就是根
                break;
        Root = i;
    }
    return Root;
}

bool Isomorphic(Tree R1,Tree R2)
{
    if((R1 == NULL)&&(R2==NULL))//兩邊都空
        return true;
    if(((R1 == NULL)&&(R2 != NULL))||((R2 == NULL)&&(R1 != NULL)))//一邊空一邊不空
        return false;
    if(T1[R1].Element != T2[R2].Element)//兩個樹的根不同
        return false;
    if((T1[R1].left==NULL)&&(T2[R2].left==NULL))//兩邊都沒有左子樹
        return Isomorphic(T1[R1].right,T2[R2].right);
    if(((T1[R1].left != NULL)&&T2[R2].left != NULL)&&((T1[T1[R1].left].Element == T2[T2[R2].left].Element)))//不需要交換左邊和右邊
        return (Isomorphic(T1[R1].left,T2[R2].left)&&Isomorphic(T1[R1].right,T2[R2].right));
    else//需要交換左邊和右邊
        return (Isomorphic(T1[R1].left,T2[R2].right)&&Isomorphic(T1[R1].right,T2[R2].left));
}



int main()
{
    Tree R1,R2;

    R1 = BuildTree(T1);
    R2 = BuildTree(T2);
    if(Isomorphic(R1,R2))
        cout<<"Yes"<<endl;
    else
        cout<<"No"<<endl;
}

相關推薦

--森林-計算機17 7-1 25 答案

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

25 答案--森林-計算機17 7-1

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

作業1--計算機17 7-1 根據後序中序遍歷輸出先序遍歷 25

7-1 根據後序和中序遍歷輸出先序遍歷 (25 分) 本題要求根據給定的一棵二叉樹的後序遍歷和中序遍歷結果,輸出該樹的先序遍歷結果。 輸入格式: 第一行給出正整數N(≤30),是樹中結點的個數。隨後兩行,每行給出N個整數,分別對應後序遍歷和中序遍歷結果,數字間以空

修理牧場 25 --Huffman-計算機17 7-1

7-1 修理牧場 (25 分) 農夫要修理牧場的一段柵欄,他測量了柵欄,發現需要N塊木頭,每塊木頭長度為整數L​i​​個長度單位,於是他購買了一條很長的、能鋸成N塊的木頭,即該木頭的長度是L​i​​的總和。 但是農夫自己沒有鋸子,請人鋸木的酬金跟這段木頭的長度成正比。為簡

根據後序中序遍歷輸出先序遍歷 25 作業1--計算機17 7-1

7-1 根據後序和中序遍歷輸出先序遍歷 (25 分) 本題要求根據給定的一棵二叉樹的後序遍歷和中序遍歷結果,輸出該樹的先序遍歷結果。 輸入格式: 第一行給出正整數N(≤30),是樹中結點的個數。隨後兩行,每行給出N個整數,分別對應後序遍歷和中序遍歷結果,數字間以空格分隔

一道老坑爹的題棧作業題2-棧及其應用-計算機17 7-1 表示式轉換 25

 7-1 表示式轉換 (25 分) 算術表示式有字首表示法、中綴表示法和字尾表示法等形式。日常使用的算術表示式是採用中綴表示法,即二元運算子位於兩個運算數中間。請設計程式將中綴表示式轉換為字尾表示式。 輸入格式: 輸入在一行中給出不含空格的中綴表示式,可

作業題3--佇列-計算機17 7-1 銀行業務佇列簡單模擬 25

7-1 銀行業務佇列簡單模擬 (25 分) 設某銀行有A、B兩個業務視窗,且處理業務的速度不一樣,其中A視窗處理速度是B視窗的2倍 —— 即當A視窗每處理完2個顧客時,B視窗處理完1個顧客。給定到達銀行的顧客序列,請按業務完成的順序輸出顧客序列。假定不考慮顧客先後到達的時

--森林-計算機17 7-2 家譜處理 30

7-2 家譜處理 (30 分) 人類學研究對於家族很感興趣,於是研究人員蒐集了一些家族的家譜進行研究。實驗中,使用計算機處理家譜。為了實現這個目的,研究人員將家譜轉換為文字檔案。下面為家譜文字檔案的例項: John Robert Frank And

作業-串-計算機17 7-1 最長對稱子串 25 四種方法求解暴力列舉+動態規劃+中心擴充套件+manacher演算法馬拉車

7-1 最長對稱子串 (25 分) 對給定的字串,本題要求你輸出最長對稱子串的長度。例如,給定Is PAT&TAP symmetric?,最長對稱子串為s PAT&TAP s,於是你應該輸出11。 輸入格式: 輸入在一行中給出長度不超過1000的非空字串

遍歷及推導遍歷結果(前序、中序後續)

二叉樹遍歷方法 下面幾種演算法是利用遞迴的方法實現的 - 前序遍歷:先列印輸出,再先序遍歷左子樹,最後先序遍歷右子樹 - 中序遍歷:中序遍歷左子樹,再列印,最後中序遍歷右子樹 - 後序遍歷:先後序遍歷左子樹,再後序遍歷右子樹,最後列印輸出 - 總結:前

作業1--計算機17 6-1高度 20

6-1 求二叉樹高度 (20 分) 本題要求給定二叉樹的高度。 函式介面定義: int GetHeight( BinTree BT ); 其中BinTree結構定義如下: typedef struct TNode *Position; typedef P

迴圈佇列及線性結構綜合-計算機17 7-2 列車排程 25

7-2 列車排程 (25 分) 火車站的列車排程鐵軌的結構如下圖所示。 兩端分別是一條入口(Entrance)軌道和一條出口(Exit)軌道,它們之間有N條平行的軌道。每趟列車從入口可以選擇任意一條軌道進入,最後從出口離開。在圖中有9趟列車,在入口處按照{8,4,2,

棧作業題2-棧及其應用-計算機17 6-1 爆記憶體函式例項 6

6-1 爆記憶體函式例項 (6 分) 本題要求實現一個遞迴函式,使用者傳入非負整型引數n,使用者依次輸出1到n之間的整數。所謂遞迴函式就是指自己呼叫自己的函式。 說明: (1)遞迴函式求解問題的基本思想是把一個大規模問題的求解歸結為一個相對較小規模問題的求解, 小規模

棧作業題2-棧及其應用-計算機17 7-2 符號配對 20

7-2 符號配對 (20 分) 請編寫程式檢查C語言源程式中下列符號是否配對:/*與*/、(與)、[與]、{與}。 輸入格式: 輸入為一個C語言源程式。當讀到某一行中只有一個句點.和一個回車的時候,標誌著輸入結束。程式中需要檢查配對的符號不超過100個。 輸出

深入理解hashmap雜湊表搜尋的恩怨情仇

前面兩篇文章介紹了hashmap的原始碼和理論,今天把剩餘的部分紅黑樹講一下。理解好紅黑樹,對我們後續對hashmap或者其他資料結構的理解都是很有好處的。比方說為什麼後面jdk要把hashmap中的單鏈表更新成紅黑樹? 要理解紅黑樹首先要弄清楚普通二叉樹的一些基本概念 父節點和子節點,這個我就不多說了。

第二作業題2-連結串列-計算機17 7-3 jmu-ds-單鏈表的基本運算 15

7-3 jmu-ds-單鏈表的基本運算 (15 分) 實現單鏈表的基本運算:初始化、插入、刪除、求表的長度、判空、釋放。 (1)初始化單鏈表L,輸出L->next的值; (2)依次採用尾插法插入元素:輸入分兩行資料,第一行是尾插法需要插入的字元資料的個數,第二行是具體

作業1-棧-計算機17 7-16 一元多項式求導 20

7-16 一元多項式求導 (20 分) 設計函式求一元多項式的導數。 輸入格式: 以指數遞降方式輸入多項式非零項係數和指數(絕對值均為不超過1000的整數)。數字間以空格分隔。 輸出格式: 以與輸入相同的格式輸出導數多項式非零項的係數和指數。數字間以空格分隔,但結尾

B排序如紅黑、BB+的區別

B樹是為了提高磁碟或外部儲存裝置查詢效率而產生的一種多路平衡查詢樹。 B+樹為B樹的變形結構,用於大多數資料庫或檔案系統的儲存而設計。 B樹相對於紅黑樹的區別 在大規模資料儲存的時候,紅黑樹往往出現由於樹的深度過大而造成磁碟IO讀寫過於頻繁,進而導致效率低下的情況

*5輸入互不相同的一組整數,構造一棵二叉排序,要求: ① 按遞減有序的順序輸出; ② 輸入一個整數,查詢該整數是否在該二叉排序中,查詢成功返回1,否則返回0; ③ 在②中,若查詢成功,則將該結

/*(5)輸入互不相同的一組整數,構造一棵二叉排序樹,要求: ① 按遞減有序的順序輸出; ② 輸入一個整數,查詢該整數是否在該二叉排序樹中,查詢成功返回1,否則返回0; ③ 在②中,若查詢成功,則將該結點從二叉排序樹中刪除。 */ #include<stdio.h&g

劍指Offerjava+題,重建

思路:先找出根節點,然後利用遞迴方法構造二叉樹 程式碼實現: import java.util.Arrays; class TreeNode{ int val; TreeNode left; TreeNode right; TreeNode(int x){val = x;} } p