7-1 樹的同構 (30 point(s))
給定兩棵樹T1和T2。若是T1能夠經過若干次左右孩子互換就變成T2,則咱們稱兩棵樹是「同構」的。例如圖1給出的兩棵樹就是同構的,由於咱們把其中一棵樹的結點A、B、G的左右孩子互換後,就獲得另一棵樹。而圖2就不是同構的。node
圖1ios
圖2數組
現給定兩棵樹,請你判斷它們是不是同構的。輸入格式:框架
輸入給出2棵二叉樹樹的信息。對於每棵樹,首先在一行中給出一個非負整數N (≤),即該樹的結點數(此時假設結點從0到N−1編號);隨後N行,第i行對應編號第i個結點,給出該結點中存儲的1個英文大寫字母、其左孩子結點的編號、右孩子結點的編號。若是孩子結點爲空,則在相應位置上給出「-」。給出的數據間用一個空格分隔。注意:題目保證每一個結點中存儲的字母是不一樣的。ide
先從大的框架主函數寫起,先無論怎麼實現先大膽用各類函數函數
方法:先創建兩棵樹並返回根結點,再判斷返回結果,根據結果輸出yes或noflex
int main() { int root1,root2; root1=input(t1); //接收數據生成一棵樹並返回根結點的標號 root2=input(t2); if(match(root1,root2)) //調用函數返回判斷結果 cout<<"Yes"; else cout<<"No"; return 0; }
先把結點的定義肯定下來spa
方法:字符型的數據,整型的左右孩子code
typedef struct { char data; int lchild,rchild; }node; //根據題意定義一個結構體放0-n號結點的信息(字母及左右孩子的標號)
創建樹blog
方法:這個就是老套路了,按照編號(下標)輸入數據和孩子編號,更改孩子結點的flag值,最後遍歷全部結點來找出根節點
int input(node t[]) { //輸入數據並返回根結點的標號 int n; char ch1,ch2; cin>>n; //輸入一棵樹總共結點數 if(n==0) return -1; //若是是空樹就直接返回 不一樣構了 bool test[n]={false}; //定義一個布爾數組來標記每一個結點是否有雙親 for(int i=0;i<n;i++) { //從0開始讀入對應標號的結點的信息 cin>>t[i].data; cin>>ch1>>ch2; if(ch1!='-') { //若是左孩子不爲空就成爲對應結點的左孩子 t[i].lchild=ch1-'0'; test[ t[i].lchild ]=true; //左孩子標號的那個結點就是有雙親的了 } else t[i].lchild=-1; //左孩子爲空則標記爲-1 if(ch2!='-') { t[i].rchild=ch2-'0'; test[ t[i].rchild ]=true; } else t[i].rchild=-1; } for(int j=0;j<n;j++) { //從0開始逐一判斷每一個結點是否有雙親 if(!test[j]) //沒有雙親的就是根結點 return j; } }
比較判斷是否同構
方法:分兩種狀況來討論
樹空的狀況1.兩棵樹都爲空 (同構) 2.一棵樹爲空另外一棵樹不爲空 (不一樣構)
樹不爲空的狀況1.結點的數據不相等(不一樣構) 2.結點數據相等繼續比較左左孩子和右右孩子(若都同構則兩棵樹同構) 3.結點數據相等但左左孩子和右右孩子不一樣構則繼續比較左右和右左孩子(若都同構則兩棵樹同構) 4.結點數據相等但左左右右,左右右左都不一樣構則兩棵樹不一樣構
int match(int r1,int r2) { //判斷是否同構 if(r1==-1&&r2==-1) return 0;//若是兩棵樹都爲空則不一樣構 if((r1==-1&&r2!=-1) || (r1!=-1&&r2==-1)) return 0; //兩棵樹一棵爲空,一棵不爲空則不一樣構 if(t1[r1].data!=t2[r2].data) return 0; //若是非空但數據不相等則不一樣構 if(match(t1[r1].lchild,t2[r2].lchild) && match(t1[r1].rchild,t2[r2].rchild)) return 1; //若是非空且數據相等則繼續比較左左 右右 if(match(t1[r1].lchild,t2[r2].rchild) && match(t1[r1].rchild,t2[r2].lchild)) return 1; //若是非空且數據相等但左左右右不相等則比較左右 右左 return 0; //以上包含了空的狀況和非空時同構的狀況最後加上不一樣構的時候 }
最後貼上所有代碼
#include <iostream> using namespace std; typedef struct { char data; int lchild,rchild; }node; //根據題意定義一個結構體放0-n號結點的信息(字母及左右孩子的標號) node t1[11],t2[11]; //定義兩個結構體類型的數組 int input(node t[]) { //輸入數據並返回根結點的標號 int n; char ch1,ch2; cin>>n; //輸入一棵樹總共結點數 if(n==0) return -1; //若是是空樹就直接返回 不一樣構了 bool test[n]={false}; //定義一個布爾數組來標記每一個結點是否有雙親 for(int i=0;i<n;i++) { //從0開始讀入對應標號的結點的信息 cin>>t[i].data; cin>>ch1>>ch2; if(ch1!='-') { //若是左孩子不爲空就成爲對應結點的左孩子 t[i].lchild=ch1-'0'; test[ t[i].lchild ]=true; //左孩子標號的那個結點就是有雙親的了 } else t[i].lchild=-1; //左孩子爲空則標記爲-1 if(ch2!='-') { t[i].rchild=ch2-'0'; test[ t[i].rchild ]=true; } else t[i].rchild=-1; } for(int j=0;j<n;j++) { //從0開始逐一判斷每一個結點是否有雙親 if(!test[j]) //沒有雙親的就是根結點 return j; } } int match(int r1,int r2) { //判斷是否同構 if(r1==-1&&r2==-1) return 0;//若是兩棵樹都爲空則不一樣構 if((r1==-1&&r2!=-1) || (r1!=-1&&r2==-1)) return 0; //兩棵樹一棵爲空,一棵不爲空則不一樣構 if(t1[r1].data!=t2[r2].data) return 0; //若是非空但數據不相等則不一樣構 if(match(t1[r1].lchild,t2[r2].lchild) && match(t1[r1].rchild,t2[r2].rchild)) return 1; //若是非空且數據相等則繼續比較左左 右右 if(match(t1[r1].lchild,t2[r2].rchild) && match(t1[r1].rchild,t2[r2].lchild)) return 1; //若是非空且數據相等但左左右右不相等則比較左右 右左 return 0; //以上包含了空的狀況和非空時同構的狀況最後加上不一樣構的時候 } int main() { int root1,root2; root1=input(t1); //接收數據生成一棵樹並返回根結點的標號 root2=input(t2); if(match(root1,root2)) //調用函數返回判斷結果 cout<<"Yes"; else cout<<"No"; return 0; }