樹的子結構 | 輸入兩棵二叉樹A和B,判斷B是不是A的子結構

面試題18:樹的子結構

1.題目描述

輸入兩棵二叉樹A和B,判斷B是不是A的子結構。二叉樹結點的定義如下:

struct BinaryTreeNode
{
    int m_nValue;
    BinaryTreeNode* m_pLeft;
    BinaryTreeNode* m_pRirht;
];

2.題目分析

例如下圖中的兩棵二叉樹,由於A中有一部分子樹的結構和B是一樣的,因此B是A的子結構。

要查找樹A中是否存在和樹B結構一樣的子樹,我們可以分成兩步:第一步在樹A中找到和B的根結點的值一樣的結點R,第二步再判斷樹A中以R爲根結點的子樹是不是包含和樹B一樣的結構。

以上面的兩棵樹爲例來詳細分析這個過程。首先我們試着在樹A中找到值爲8(樹B的根結點的值)的結點。從樹A的根結點開始遍歷,我們發現它的根結點的值就是8.接着我們就去判斷樹A的根結點下面的子樹是不是含有和樹B一樣的結構。在樹A中,根結點的左子結點的值是8,而樹B的根結點的左子結點是9,對應的兩個結點不同。

因此我們仍然需要遍歷樹A,接着查找值爲8的結點。我們在樹的第二層中找到了一個值爲8的結點,然後進行第二步判斷,即判斷這個結點下面的子樹是否含有和樹B一樣結構的子樹。於是我們遍歷這個結點下面的子樹,先後得到兩個子結點9和2,這和樹B的結構完全相同。此時我們在樹A中找到了一個和樹B的結構一樣的子樹,因此樹B是樹A的子結構。

第一步在樹A中查找與根結點的值一樣的結點,這實際上就是樹的遍歷。在上述代碼中,我們遞歸調用 HasSubtree遍歷二叉樹A。如果發現某結點的值和樹B的頭結點的值相同,則調用 Does lHave Tree2,做第二步判斷。

第二步是判斷樹A中以R爲根結點的子樹是不是和樹B具有相同的結構。同樣,我們也可以用遞歸的思路來考慮:如果結點R的值和樹B的根結點不相同,則以R爲根結點的子樹和樹B肯定不具有相同的結點;如果它們的值相同,則遞歸地判斷它們各自的左右結點的值是不是相同。遞歸的終止條件是我們到達了樹A或者樹B的葉結點。

3.code

bool HasSubtree(BinaryTreeNode* pRoot1,BinaryTreeNode* pRoot2)
{
    bool result = false;
    
    if(pRoot1 != NULL && pRoot2 != NULL)
    {
        if(pRoot1->m_nValue == pRoot2->m_nValue)
        {
            result = DoesTree1HaveTree2(pRoot1,pRoot2);
        }
        if(!result)
        {
            result = HasSubtree(pRoot1->m_pLeft,pRoot2);
        }
        if(!result)
        {
            result = HasSubtree(pRoot1->m_pRight,pRoot2);
        }
    }
    return result;
}

bool DoesTree1HaveTree1(BinaryTreeNode* pRoot1,BinaryTreeNode* pRoot2)
{
    if(pRoot2 == NULL)    return true;//此時pRoot2的所有節點都已經遍歷完畢

    if(pRoot1 == NULL)    return false;//此時pRoot2還沒遍歷完畢,但是pRoot1已經遍歷完畢

    if(pRoot1->m_Value != pRoot2->m_nValue)
    {
        return false;
    }
    
    return DoesTree1HaveTree2(pRoot1->m_pLeft,pRoot2->m_pLeft) 
    &&
    DoesTree1HaveTree2(pRoot1->m_pRight,pRoot2->m_pRight);
} 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章