/*
樹的子結構:
輸入兩顆二叉樹a和b,判斷b是不是a的子結構。
例如:樹a: 樹b
8 8
87 9 292
47過程總結:
在樹a中查詢與樹b中根節點一樣的值,然後遞迴比較兩者的左子樹和右子樹是否相同
遞迴出口是:樹b的左右子樹為空
這道題目有兩個遞迴:
主遞迴:用於確定樹a中的那個根節點與樹b的根節點進行比較,一旦相同,呼叫子遞迴
子遞迴:用於判斷兩個樹中是否具有相同的子結構。這裡注意:如果小樹先遞迴到空,說明是有子結構的。
如果兩個根節點(前根遍歷)都不同或者大樹已經為空,肯定不是。如果根節點相同,那麼分別遍歷:
大樹與小樹的左子樹 與 大樹與小數的右子樹 是否都具有子結構
輸入:輸入可能包含多個測試樣例,輸入以eof結束。
對於每個測試案例,輸入的第一行乙個整數n,m(1<=n<=1000,1<=m<=1000):n代表將要輸入的二叉樹a的節點個數(節點從1開始計數),m代表將要輸入的二叉樹b的節點個數(節點從1開始計數)。接下來一行有n個數,每個數代表a樹中第i個元素的數值,接下來有n行,第乙個數ki代表第i個節點的子孩子個數,接下來有ki個樹,代表節點i子孩子節點標號。接下來m+1行,與樹a描述相同。
輸出:對應每個測試案例,
若b是a的子樹輸出」yes」(不包含引號)。否則,輸出「no」(不包含引號)。
樣例輸入:
7 38 8 7 9 2 4 7
2 2 3
2 4 500
2 6 700
8 9 2
2 2 300
1 1203
0樣例輸出:
yesno
*//*
關鍵:1
if(psmallhead2 == null)//易錯,這裡小樹為空必須放在前面,否則會出現大樹也為空,但大樹放在前面返回為假的情況
if(pbighead1 == null)//遞迴出口
2return judgesubtree(pbighead1->_left,psmallhead2->_left) && judgesubtree(pbighead1->_right,psmallhead2->_right);//兩個根節點值相等,就返回左右子樹的判定情況
3if(pbighead1->_ival == psmallhead2->_ival)//如果頭結點對應的值相同,則進行遞迴
if(!bres)//這裡,如果左子樹如果找到,後面右子樹就不需要查詢了,因此需要加判定條件
*/#include
#include
const int maxsize = 1001;//1000個節點
typedef struct treenode
treenode;
treenode nodearr1[maxsize];
treenode nodearr2[maxsize];
int _iindex1;
int _iindex2;
treenode* createnode1()
treenode* createnode2()
//建大樹
void buildbigtree(treenode** phead,int* parr,int n,treenode* (*pfun)())//如果剛開始就穿入的是空指標
for(int i = 0 ; i < n ; i++)//先把各個單獨的節點建立起來,其中首節點不需要建立,因為已經建立了
else//對於頭結點賦值
}//接下來構建二叉樹的指向問題,共有n行,代表n個節點
for(int j = 1 ; j <= n; j++)
else if(inum == 1)//如果只有乙個節點,預設為子節點編號左節點
else if(inum == 2)//構建該節點的左右子節點}}
//建小樹
void buildsmalltree(treenode** phead,int* parr,int n,treenode* (*pfun)())
for(int i = 0 ; i < n ; i++)//先把各個單獨的節點建立起來,其中首節點不需要建立,因為已經建立了
else//對於頭結點賦值
}//接下來構建二叉樹的指向問題,共有n行,代表n個節點
for(int j = 1 ; j <= n; j++)
else if(inum == 1)//如果只有乙個節點,預設為子節點編號左節點
else if(inum == 2)//構建該節點的左右子節點}}
//主遞迴函式:設定頭結點,對於頭結點相同比較,一旦發現兩者從頭結點向下遍歷。
//判斷是否具有相同子結構的次遞迴函式:若發現頭結點的值不同,則立即返回。否則返回左子樹的比較情況和右子樹
//的比較情況。一旦小樹變空,說明是正確的。大數變空則是錯誤的。(遞迴出口)
//因為這裡是遍歷,因此不需要用二級指標。只有當需要改變的時候採用二級指標
bool judgesubtree1(treenode* pbighead1,treenode* psmallhead2)
if(pbighead1 == null)//遞迴出口
if(pbighead1->_ival == psmallhead2->_ival)//兩個根節點值相等,就返回左右子樹的判定情況
else
}bool judgesubtree(treenode* pbighead1,treenode* psmallhead2)
if(pbighead1 == null)//遞迴出口
if(pbighead1->_ival != psmallhead2->_ival)
return judgesubtree(pbighead1->_left,psmallhead2->_left) && judgesubtree(pbighead1->_right,psmallhead2->_right);//兩個根節點值相等,就返回左右子樹的判定情況
}bool issubtree1(treenode* pbighead1,treenode* psmallhead2)
bool bres = false;//預設為假
if(pbighead1->_ival == psmallhead2->_ival)//如果頭結點對應的值相同,則進行遞迴
if(!bres)//這裡,如果左子樹如果找到,後面右子樹就不需要查詢了,因此需要加判定條件
}return bres;
}bool issubtree(treenode* pbighead1,treenode* psmallhead2)
if(!bres)//這裡,如果左子樹如果找到,後面右子樹就不需要查詢了,因此需要加判定條件}}
return bres;
}void process()
//建大樹
int iarr1[maxsize];
_iindex1 = 0;//注意結點編號從1開始,注意記錄頭結點
memset(nodearr1,null,sizeof(nodearr1));
treenode* head1 = createnode1();//不能穿入空指標
treenode** phead1 = &head1;
for(int i = 0 ; i < n ; i++)//接受樹a的n各節點的值,這裡應該順便將各個節點建立出來
buildbigtree(phead1,iarr1,n,createnode1);
//建小樹
int iarr2[maxsize];
_iindex2 = 0;//注意結點編號從1開始,注意記錄頭結點
memset(nodearr2,null,sizeof(nodearr2));
treenode* head2 = createnode2();//不能穿入空指標
treenode** phead2 = &head2;
for(int j = 0 ; j < m ; j++)//接受樹a的n各節點的值,這裡應該順便將各個節點建立出來
buildsmalltree(phead2,iarr2,m,createnode2);
//對已經建立的樹,判斷大樹是否包含小樹的子結構
bool bres = issubtree(head1,head2);
if(bres)
else}}
int main(int argc,char* argv)
劍指Offer 面試題18 樹的子結構
輸入兩棵二叉樹a,b,判斷b是不是a的子結構。ps 我們約定空樹不是任意乙個樹的子結構 分析 這裡說的子結構不是子樹,只是根據值來判斷,更像是 包含 關係吧。首先需要在a樹中找到和b根節點值一樣的結點,然後判斷a的子樹和b是否結構和值相同。在a中找到和b的根結點值相同的操作等同於二叉樹遍歷,用先序遍...
劍指offer 面試題26 樹的子結構
完整 位址 輸入兩棵二叉樹a,b,判斷b是不是a的子結構。ps 我們約定空樹不是任意乙個樹的子結構 找到樹a中與樹b根節點值相同的節點,設樹a中該節點為subroot 在遍歷樹b的同時,遍歷subroot,如果遍歷完樹b發現subroot中沒有與b不一致的地方,則b是a的子結構 遍歷樹b時,發現su...
劍指offer 面試題26 樹的子結構
輸入兩棵二叉樹a和b,判斷b是不是a的子結構。約定空樹不是任意乙個樹的子結構 b是a的子結構,即 a中有出現和b相同的結構和節點值。例如 給定的樹 a 3 4 5 1 2 給定的樹 b 4 1返回 true,因為 b 與 a 的乙個子樹擁有相同的結構和節點值。示例 1 輸入 a 1,2,3 b 3,...