歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

比較兩個二叉樹是否相同(結構和數據),遞歸和非遞歸

1、二叉樹定義

typedef struct BTreeNodeElement_t_ {
    void *data;
} BTreeNodeElement_t;


typedef struct BTreeNode_t_ {
    BTreeNodeElement_t    *m_pElemt;
    struct BTreeNode_t_    *m_pLeft;
    struct BTreeNode_t_    *m_pRight;
} BTreeNode_t;

2、比較兩個二叉樹結構是否相同,不涉及存儲的數據

(1)遞歸方式

如果兩個二叉樹pRoot都為空樹,則自然相同,返回true;

如果兩個二叉樹pRoot一個為空樹,另一個不為空樹,則不相同,返回false;

如果兩個二叉樹都不為空樹,則需要分別比較左右子樹後,根據比較結果共同判定,只要有一個為false,則返回false。

bool  BTreeCompare( BTreeNode_t *pRoot1, BTreeNode_t *pRoot2)
{
    //如果都為空樹,則相同
    if( pRoot1 == NULL && pRoot2 == NULL )
        return true;
    //如果一個為空,一個不為空,則不相同
    if( ( pRoot1 != NULL && pRoot2 == NULL )  ||
        ( pRoot1 == NULL && pRoot2 != NULL ) )
        return false;
    //如果都不為空,則 需要比較左右子樹後,再根據比較結果斷定
    bool  leftCmp = BTreeCompare( pRoot1->m_pLeft, pRoot2->m_pLeft);
    bool  rightCmp = BTreeCompare( pRoot1->m_pRight, pRoot2->m_pRight);

    return ( leftCmp && rightCmp );
}

(2)非遞歸方式

借助隊列實現

實現算法:

首先將給定根節點pRoot1和pRoot2都入隊

第一步:當兩個隊列未空時,分別獲取兩個樹的當前層次中節點總數(即當前隊列中節點個數),先比較節點個數是否相同,如果不相同,則兩個樹自然不同;如果節點個數相同,需要出隊進行比較。如果有一個隊列未空,則退出比較。

第二步:如果有一個隊列未空,則清空隊列並返回不同。

bool  BTreeCompare(BTreeNode_t *pRoot1, BTreeNode_t *pRoot2)
{
    if( pRoot1 == NULL && pRoot2 == NULL )
        return false;

    queue <BTreeNode_t *> que1;
    queue <BTreeNode_t *> que2;

    que1.push(pRoot1);
    que2.push(pRoot2);

    int curLevelNodeTotal1 = 0;
    int curLevelNodeTotal2 = 0;

    bool flag = true; //作為比較不一致時跳出標識
    while( ( !que1.empty()) && ( !que2.empty())) //當兩個隊列均不為空時,才進行比較
    {
        curLevelNodeTotal1 = que1.size();  //獲取樹1的當前層節點總數
        curLevelNodeTotal2 = que2.size(); //獲取樹2的當前層節點總數
        if( curLevelNodeTotal1 != curLevelNodeTotal2){
            flag = false;//當前層節點總數都不一致,不需要比較了,直接跳出
            break;
        }
        int cnt1 = 0;//遍歷本層節點時的計數器
        int cnt2 = 0;
        while( cnt1 < curLevelNodeTotal1  && cnt2 < curLevelNodeTotal2){
            ++cnt1;
            ++cnt2;
            pRoot1 = que1.front();
            que1.pop();
            pRoot2 = que2.front();
            que2.pop();

            //判斷pRoot1和pRoot2左右節點結構是否相同
            if( ( pRoot1->m_pLeft != NULL && pRoot2->m_pLeft == NULL )    ||
                ( pRoot1->m_pLeft == NULL && pRoot2->m_pLeft != NULL )    ||
                ( pRoot1->m_pRight != NULL && pRoot2->m_pRight == NULL )    ||
                ( pRoot1->m_pRight == NULL && pRoot2->m_pRight != NULL )
            ){
                flag = false;
                break;
            }
 
            //將左右節點入隊
            if( pRoot1->m_pLeft != NULL )
                que1.push( pRoot1->m_pLeft);
            if( pRoot1->m_pRight != NULL )
                que1.push( pRoot1->m_pRight);
            if( pRoot2->m_pLeft != NULL )
                que2.push( pRoot2->m_pLeft);
            if( pRoot2->m_pRight != NULL )
                que2.push( pRoot2->m_pRight);
        }

        if( flag == false )
            break;
    }

    //如果比較標志為false,則不相同
    if( flag == false ){
        while( !que1.empty() )
            que1.pop();
        while( !que2.empty())
            que2.pop();

        return false;
    }

    return true;
}

3、比較兩個二叉樹結構和數據是否同時相同,即兩個一模一樣的樹

與上面的不同之處在於:在比較結構是否相同之後,需要比較當前節點的數據是否一致。

算法是一致的,只需要添加一行代碼即可。

(1)遞歸方式:

 

bool  BTreeCompare( BTreeNode_t *pRoot1, BTreeNode_t *pRoot2)
{
    //如果都為空樹,則相同
    if( pRoot1 == NULL && pRoot2 == NULL )
        return true;
    //如果一個為空,一個不為空,則不相同
    if( ( pRoot1 != NULL && pRoot2 == NULL )  ||
        ( pRoot1 == NULL && pRoot2 != NULL ) )
        return false;
    //比較當前節點中的數據
    if( pRoot1->m_pElemt != pRoot2->m_pElemt)
        return false;
    //如果都不為空,則 需要比較左右子樹後,再根據比較結果斷定
    bool  leftCmp = BTreeCompare( pRoot1->m_pLeft, pRoot2->m_pLeft);
    bool  rightCmp = BTreeCompare( pRoot1->m_pRight, pRoot2->m_pRight);

    return ( leftCmp && rightCmp );
}

(2)非遞歸方式

bool  BTreeCompare(BTreeNode_t *pRoot1, BTreeNode_t *pRoot2)
{
    if( pRoot1 == NULL && pRoot2 == NULL )
        return false;


    queue <BTreeNode_t *> que1;
    queue <BTreeNode_t *> que2;


    que1.push(pRoot1);
    que2.push(pRoot2);


    int curLevelNodeTotal1 = 0;
    int curLevelNodeTotal2 = 0;


    bool flag = true; //作為比較不一致時跳出標識
    while( ( !que1.empty()) && ( !que2.empty())) //當兩個隊列均不為空時,才進行比較
    {
        curLevelNodeTotal1 = que1.size();  //獲取樹1的當前層節點總數
        curLevelNodeTotal2 = que2.size(); //獲取樹2的當前層節點總數
        if( curLevelNodeTotal1 != curLevelNodeTotal2){
            flag = false;//當前層節點總數都不一致,不需要比較了,直接跳出
            break;
        }
        int cnt1 = 0;//遍歷本層節點時的計數器
        int cnt2 = 0;
        while( cnt1 < curLevelNodeTotal1  && cnt2 < curLevelNodeTotal2){
            ++cnt1;
            ++cnt2;
            pRoot1 = que1.front();
            que1.pop();
            pRoot2 = que2.front();
            que2.pop();

            //比較當前節點中數據是否一致
            if( pRoot1->m_pElemt != pRoot2->m_pElemt ){
                flag = false;
                break;
            }
            //判斷pRoot1和pRoot2左右節點結構是否相同
            if( ( pRoot1->m_pLeft != NULL && pRoot2->m_pLeft == NULL )    ||
                ( pRoot1->m_pLeft == NULL && pRoot2->m_pLeft != NULL )    ||
                ( pRoot1->m_pRight != NULL && pRoot2->m_pRight == NULL )    ||
                ( pRoot1->m_pRight == NULL && pRoot2->m_pRight != NULL )
            ){
                flag = false;
                break;
            }
 
            //將左右節點入隊
            if( pRoot1->m_pLeft != NULL )
                que1.push( pRoot1->m_pLeft);
            if( pRoot1->m_pRight != NULL )
                que1.push( pRoot1->m_pRight);
            if( pRoot2->m_pLeft != NULL )
                que2.push( pRoot2->m_pLeft);
            if( pRoot2->m_pRight != NULL )
                que2.push( pRoot2->m_pRight);
        }


        if( flag == false )
            break;
    }

    //如果比較標志為false,則不相同
    if( flag == false ){
        while( !que1.empty() )
            que1.pop();
        while( !que2.empty())
            que2.pop();


        return false;
    }


    return true;
}

二叉樹的常見問題及其解決程序 http://www.linuxidc.com/Linux/2013-04/83661.htm

【遞歸】二叉樹的先序建立及遍歷 http://www.linuxidc.com/Linux/2012-12/75608.htm

在JAVA中實現的二叉樹結構 http://www.linuxidc.com/Linux/2008-12/17690.htm

【非遞歸】二叉樹的建立及遍歷 http://www.linuxidc.com/Linux/2012-12/75607.htm

二叉樹遞歸實現與二重指針 http://www.linuxidc.com/Linux/2013-07/87373.htm

二叉樹先序中序非遞歸算法 http://www.linuxidc.com/Linux/2014-06/102935.htm

輕松搞定面試中的二叉樹題目 http://www.linuxidc.com/linux/2014-07/104857.htm

Copyright © Linux教程網 All Rights Reserved