1. 程式人生 > >資料結構——二叉查詢樹的詳細實現(c++)

資料結構——二叉查詢樹的詳細實現(c++)

本文實現了二叉查詢樹的前序遍歷(遞迴與非遞迴)、中序遍歷(遞迴與非遞迴)、後序遍歷(遞迴與非遞迴)、插入過程、刪除過程、查詢過程等。

二叉樹的簡單介紹:
1、二叉樹中的每個節點都不能有多餘兩個的兒子。
2、二叉樹的深度要比N小得多。

假設每個節點被指定一個關鍵字值(所有關鍵字是整數、互異的)。

二叉查詢樹的性質:
1、左子樹的所有節點值均小於根節點值。
2、右子樹的所有節點值均大於根節點值。
3、左右子樹都滿足上述兩個條件。

插入過程:
1、若當前二叉樹為空,則插入的元素為根節點。
2、若插入的元素值小於根節點值,則遞迴從根節點的左子樹中找到可插入位置。
3、若插入的元素值大於根節點值,則遞迴從根節點的右子樹中找到可插入位置。

刪除過程:
1、待刪除節點Z為葉子節點,則直接刪除該節點。修改父節點的指標。
2、待刪除節點Z為單支節點(只有左子樹或者右子樹),讓Z的子樹與Z的父節點相連,刪除節點Z。
3、待刪除節點Z左右子樹都不為空。
方法一:找到Z的後繼節點y,因為y一定沒有左子樹,所以可以直接刪除y,並讓y的父親節點成為y的右子樹的父親節點。用y替換Z。
方法二:找到Z的前驅節點x,x一定沒有右子樹,所以可以直接刪除x,並讓x的父親節點成為x的左子樹的父親節點。用x替換Z。

查詢過程:
1、若待查詢的元素值和根節點相同,則返回根節點。
2、若待查詢的元素值小於根節點的元素值,則遞迴從根節點的左子樹中查詢。
3、若待查詢的元素值大於根節點的元素值,則遞迴從根節點的右子樹中查詢。

遍歷過程:
1、前序遍歷(遞迴和非遞迴兩種):先根節點,後左孩子節點,再右孩子結點。
2、中序遍歷(遞迴和非遞迴兩種):先左孩子結點,後根節點,再右孩子結點。
3、後序遍歷(遞迴和非遞迴兩種):先做孩子節點,後右孩子結點,再根節點。

獲取最大元素的節點:
1、如果根節點無右子樹,則返回根節點。
2、依次查詢根節點的右子樹節點,返回右子樹的最後一個右節點。

獲取最小元素的節點:
1、如果根節點無左子樹,則返回根節點。
2、依次查詢跟節點的左子樹節點,返回左子樹的最後一個左節點。

依次插入資料(15,3,20,8,10,18,6,1,26)之後的二叉樹結構如下:
這裡寫圖片描述

程式碼如下:

#include <iostream>
#include <stack>
using namespace std;

typedef struct STreeNode* pSTreeNode;
typedef int TreeKeyType;

struct STreeNode 
{
    TreeKeyType key;
    pSTreeNode pLeftChild;
    pSTreeNode pRightChild;

    STreeNode( TreeKeyType Value )
    {
        key = Value;
        pLeftChild = NULL;
        pRightChild = NULL;
    }
};

class CBinTree
{
public:
    CBinTree();
    ~CBinTree();

    void Insert( TreeKeyType Value );
    void Insert( pSTreeNode pNode, TreeKeyType Value );

    pSTreeNode Search( TreeKeyType Value );
    pSTreeNode Search( pSTreeNode pNode, TreeKeyType Value );

    void Delete( TreeKeyType Value );

    void Preorder( );       //  前序遍歷,非遞迴方法(借用堆疊)
    void Inorder( );        //  中序遍歷,非遞迴方法(借用堆疊)
    void Postorder( );      //  後序遍歷,非遞迴方法(借用堆疊)

    void PreorderRecursively( pSTreeNode pNode );   //  前序遍歷,遞迴呼叫
    void InorderRecursively( pSTreeNode pNode );    //  中序遍歷,遞迴呼叫
    void PostorderRecursively( pSTreeNode pNode );  //  後序遍歷,遞迴呼叫

    pSTreeNode GetMaxKey();     //  獲得二叉查詢樹中元素值最大的節點
    pSTreeNode GetMinKey();     //  獲得二叉查詢樹中元素值最小的節點

    void FreeMemory( pSTreeNode pNode );    //  釋放記憶體
public:
    pSTreeNode pRoot;
};

CBinTree::CBinTree()
{
    pRoot = NULL;
}

CBinTree::~CBinTree()
{
    if ( pRoot == NULL )
        return;

    FreeMemory( pRoot );
}

void CBinTree::FreeMemory( pSTreeNode pNode )
{
    if ( pNode == NULL )
        return;

    if ( pNode->pLeftChild != NULL )
        FreeMemory( pNode->pLeftChild );

    if ( pNode->pRightChild != NULL )
        FreeMemory( pNode->pRightChild );

    delete pNode;
    pNode = NULL;
}

void CBinTree::Insert( TreeKeyType Value )
{
    if ( pRoot == NULL )
        pRoot = new STreeNode( Value );
    else
        Insert( pRoot, Value );
}

void CBinTree::Insert( pSTreeNode pNode, TreeKeyType Value )
{
    if ( pNode->key > Value )
    {
        if ( pNode->pLeftChild == NULL)
            pNode->pLeftChild = new STreeNode( Value );
        else
            Insert( pNode->pLeftChild, Value );
    }
    else
    {
        if ( pNode->pRightChild == NULL)
            pNode->pRightChild = new STreeNode( Value );
        else
            Insert( pNode->pRightChild, Value );
    }
}

pSTreeNode CBinTree::Search( TreeKeyType Value )
{
    return Search( pRoot, Value );
}

pSTreeNode CBinTree::Search( pSTreeNode pNode, TreeKeyType Value )
{
    if ( pNode == NULL )
        return NULL;

    if ( pNode->key == Value )
        return pNode;
    else
    {
        if ( pNode->key > Value )
            return Search( pNode->pLeftChild, Value );
        else
            return Search( pNode->pRightChild, Value );
    }
}

void CBinTree::Delete( TreeKeyType Value )
{
    pSTreeNode pParentNode = pRoot;
    pSTreeNode pFindNode = pRoot;
    //  找到Value元素對應的節點
    while ( pFindNode != NULL )
    {
        if ( pFindNode->key == Value )
            break;

        pParentNode = pFindNode;
        if ( pFindNode->key > Value )
            pFindNode = pFindNode->pLeftChild;
        else
            pFindNode = pFindNode->pRightChild;
    }

    if ( pFindNode == NULL )
        return;


    //  處理Value元素的父節點和Value元素的節點
    if ( pFindNode->pLeftChild == NULL || pFindNode->pRightChild == NULL )
    {
        //  一個子結點為空或者兩個子結點都為空
        pSTreeNode pTemp = NULL;
        if ( pFindNode->pLeftChild != NULL)
            pTemp = pFindNode->pLeftChild;
        else if ( pFindNode->pRightChild != NULL )
            pTemp = pFindNode->pRightChild;

        if ( pParentNode->pLeftChild == pFindNode )
            pParentNode->pLeftChild = pTemp;
        else
            pParentNode->pRightChild = pTemp;

        delete pFindNode;
        pFindNode = NULL;
    }
    else
    {
        //  找到前驅節點
        pSTreeNode pTemp = pFindNode->pLeftChild;
        pSTreeNode pTempParent = pFindNode;

        while ( pTemp->pRightChild != NULL )
        {
            pTempParent = pTemp;
            pTemp = pTemp->pRightChild; 
        }

        pFindNode->key = pTemp->key;
        pTempParent->pRightChild = NULL;
        delete pTemp;
        pTemp = NULL;
    }
}

void CBinTree::Preorder(  )
{
    if ( pRoot == NULL )
    {
        cout << "二叉樹為空!" << endl;
        return;
    }

    stack<pSTreeNode> StackTree;
    pSTreeNode pNode = pRoot;
    while( pNode != NULL || !StackTree.empty())
    {
        while ( pNode != NULL )
        {
            cout << " " << pNode->key << " ";
            StackTree.push(pNode);
            pNode = pNode->pLeftChild;
        }

        pNode = StackTree.top();
        StackTree.pop();
        pNode = pNode->pRightChild;
    }

}

void CBinTree::Inorder( )
{
    if ( pRoot == NULL )
    {
        cout << "二叉樹為空!" << endl;
        return;
    }

    stack<pSTreeNode> StackTree;
    pSTreeNode pNode = pRoot;
    while ( pNode != NULL || !StackTree.empty() )
    {
        while ( pNode != NULL )
        {
            StackTree.push( pNode );
            pNode = pNode->pLeftChild;
        }

        pNode = StackTree.top();
        StackTree.pop();
        cout << " " << pNode->key << " ";
        pNode = pNode->pRightChild;
    }
}


//  藉助變數visited表示是否訪問過該根節點。訪問過的話,這輸出。
void CBinTree::Postorder( )
{
    if ( pRoot == NULL )
    {
        cout << "二叉樹為空!" << endl;
        return;
    }

    stack< pair<pSTreeNode, bool>> StackTree;
    StackTree.push( make_pair( pRoot, false ));

    while ( !StackTree.empty() )
    {
        pSTreeNode pNode = StackTree.top().first;
        bool bVisited = StackTree.top().second;


        if (pNode == NULL)
        {
            StackTree.pop();
            continue;
        }

        if (bVisited)
        {
            cout << " " << pNode->key << " ";
            StackTree.pop();
        }
        else
        {
            StackTree.top().second = true;
            StackTree.push( make_pair( pNode->pRightChild, false));
            StackTree.push( make_pair( pNode->pLeftChild, false));
        }
    }
}

void CBinTree::PreorderRecursively( pSTreeNode pNode )
{
    if (pNode == NULL)
        return;

    cout << " " << pNode->key << " ";
    PreorderRecursively( pNode->pLeftChild );
    PreorderRecursively( pNode->pRightChild );
}

void CBinTree::InorderRecursively( pSTreeNode pNode )
{
    if (pNode == NULL)
        return;

    InorderRecursively( pNode->pLeftChild );
    cout << " " << pNode->key << " ";
    InorderRecursively( pNode->pRightChild );
}

void CBinTree::PostorderRecursively( pSTreeNode pNode )
{
    if (pNode == NULL)
        return;

    PostorderRecursively( pNode->pLeftChild );
    PostorderRecursively( pNode->pRightChild );
    cout << " " << pNode->key << " ";
}

int main()
{
    CBinTree* pBinTree = new CBinTree();
    if ( pBinTree == NULL )
        return 0;

    pBinTree->Insert( 15 );
    pBinTree->Insert( 3 );
    pBinTree->Insert( 20 );
    pBinTree->Insert( 8 );
    pBinTree->Insert( 10 );
    pBinTree->Insert( 18);
    pBinTree->Insert( 6 );
    pBinTree->Insert( 1);
    pBinTree->Insert( 26);

    pSTreeNode pRoot = pBinTree->pRoot;

    cout << " 非遞迴前序遍歷   :" ;
    pBinTree->Preorder();
    cout << endl;

    cout << " 遞迴前序遍歷    :" ;
    pBinTree->PreorderRecursively( pRoot );
    cout << endl;

    cout << " 非遞迴中序遍歷   :" ;
    pBinTree->Inorder();
    cout << endl;

    cout << " 遞迴中序遍歷    :" ;
    pBinTree->InorderRecursively( pRoot );
    cout << endl;

    cout << " 非遞迴後序遍歷   :" ;
    pBinTree->Postorder();
    cout << endl;

    cout << " 遞迴後續遍歷    :";
    pBinTree->PostorderRecursively( pRoot );
    cout << endl;

    pSTreeNode pMaxNode = pBinTree->GetMaxKey();
    pSTreeNode pMinNode = pBinTree->GetMinKey();
    if ( pMaxNode != NULL )
        cout << " 該二叉查詢樹的最大元素是:" << pMaxNode->key << endl;

    if (pMinNode != NULL )
        cout << " 該二叉查詢樹的最小元素是:" << pMinNode->key << endl;

    TreeKeyType DeleteKey = 15;
    pSTreeNode pSearchNode = pBinTree->Search( DeleteKey );
    if ( pSearchNode != NULL )
        cout << " 需要查詢的元素是:" << DeleteKey << ", 實際查詢到的元素是:" << pSearchNode->key << endl;
    else
        cout << " 沒有查詢到元素" << DeleteKey << endl;
    pBinTree->Delete( DeleteKey );
    cout << " 刪除元素" << DeleteKey << "之後的遞迴前序遍歷:";
    pBinTree->PreorderRecursively( pRoot );
    cout << endl;

    DeleteKey = 1;
    pBinTree->Delete( DeleteKey );
    cout << " 刪除元素" << DeleteKey << "之後的遞迴前序遍歷:";
    pBinTree->PreorderRecursively( pRoot );
    cout << endl;

    DeleteKey = 8;
    pBinTree->Delete( DeleteKey );
    cout << " 刪除元素" << DeleteKey << "之後的遞迴前序遍歷:";
    pBinTree->PreorderRecursively( pRoot );
    cout << endl;

    DeleteKey = 26;
    pBinTree->Delete( DeleteKey );
    cout << " 刪除元素" << DeleteKey << "之後的遞迴前序遍歷:";
    pBinTree->PreorderRecursively( pRoot );
    cout << endl;

    delete pBinTree;
    pBinTree = NULL;
    system( "pause" );
    return 1;
}

執行結果如下:
這裡寫圖片描述