C++實現二叉查找樹,有興趣的可以互相交流

最近在研究數據結構這本書,自己動手實現的一個二叉查找排序樹的類BinSortTree,實現數據的插入,查找,刪除,層序遍歷,中序遍歷等操作,熟悉數據結構的朋友都知道,根據二叉排序樹的定義,中序遍歷後得到的序列就是按照從小到大的順序排列的,而最後刪除二叉排序樹的時候,要先刪除子節點,才能刪除父節點,其實就是一個後續遍歷的過程。現在把代碼分享一下,供大家參考學習。其實這個跟stl的set容器已經十分相似,只是set使用查找性能更優越的紅黑樹來實現

BinSortTree.h

//二叉排序樹的類,實現插入數據,查找數據,插入數據、刪除數據
#include <iostream>

//定義節點結構體
class Node
{
    public:
        int nData;//數據
        Node *pLeftChild;//左子樹
        Node *pRightChild;//右子樹
        Node(int nData):pLeftChild(NULL),pRightChild(NULL),nData(nData)
    {
    }
};

//定義排序樹的類
class BinSortTree
{
    public:
        BinSortTree();
        ~BinSortTree();//在析構函數中釋放所有分配的節點
        bool Insert(int nData);//插入一個節點
        bool Erase(int nErase);//根據關鍵字刪除節點
        int  GetSize() { return m_nSize;}
        //根據關鍵字查找指定的節點,如果找到了,則返回該節點的指針
        //如果沒有找到,返回NULL
        Node* Find(int nFind);
        void Traversal(int nType = 0);//遍歷二叉樹,,0爲中序遍歷,1爲層序遍歷

    private:
        Node *m_pRoot;//根節點
        int   m_nSize;//節點的個數

    private:
        void DeleteNode(Node *pNode);
        void InorderTraversal(Node *pNode);//中序遍歷二叉樹
        void LevelOrderTraversal(Node *pNode);//層序遍歷
        bool Erase(Node **pRoot,int nData);
};

BinSortTree.cpp

#include <iostream>
#include <set>
#include <queue>
#include "BinSortTree.h"
using namespace std;

BinSortTree::BinSortTree()
{
    m_pRoot = NULL;
    m_nSize = 0;
}

BinSortTree::~BinSortTree()
{
    //析構每一個節點
    if (NULL != m_pRoot)
    {
        DeleteNode(m_pRoot); 
    }
}

void BinSortTree::DeleteNode(Node *pNode)
{
    //檢查該節點是否存在左子樹或者右子樹,如果有,遞歸調用刪除
    if (NULL != pNode->pLeftChild)
    {
        DeleteNode(pNode->pLeftChild);
    }
    if (NULL != pNode->pRightChild)
    {
        DeleteNode(pNode->pRightChild);
    }
    cout << "刪除節點:" << pNode->nData << endl;
    delete pNode;
}


Node* BinSortTree::Find(int nFind)
{
    Node *pTemp = m_pRoot;
    //類似於二分查找
    while(pTemp != NULL)
    {
        if (nFind == pTemp->nData)
        {
            //說明已經找到,返回這個指針
            return pTemp;
        }
        else if (nFind < pTemp->nData)
        {
            //從左子樹中查找
            pTemp = pTemp->pLeftChild;
        }
        else
        {
            pTemp = pTemp->pRightChild;
        }
    }

    return NULL;
}

bool BinSortTree::Insert(int nData) 
{
    Node *pPre = m_pRoot;
    Node *pNext = m_pRoot;
    //先在樹中查找,如果找到了就返回,如果沒有找到,則在最後一個節點插入
    while(pNext != NULL)
    {

        pPre = pNext;
        if (nData == pNext->nData)
        {
            return false;
        }
        else if (nData < pNext->nData)
        {
            pNext = pNext->pLeftChild;
        }
        else
        {
            pNext = pNext->pRightChild;
        }

    }
    //說明沒有找到,則插入一個新節點
    Node* pNew = new Node(nData);
    //如果是一棵空樹,則直接插入
    if (m_pRoot == NULL)
    {
        m_pRoot = pNew;
        ++m_nSize;//節點數加1
        return true;
    }
    //如果不是一棵空樹,判斷是插入到最後一個節點的左子樹還是右子樹
    if (nData < pPre->nData)
    {
        pPre->pLeftChild = pNew;
    }
    else
    {
        pPre->pRightChild = pNew;
    }

    ++m_nSize;
    return true;
}

bool BinSortTree::Erase(int nData)
{
    return Erase(&m_pRoot, nData);
}

bool BinSortTree::Erase(Node **pRoot, int nData)
{
    Node **pPre = pRoot;//保存指向刪除節點指針的指針,便於以後修改
    Node *pFind = *pRoot;
    //先在樹中查找
    while(pFind != NULL)
    {
        if (nData == pFind->nData)
        {
            break;
        }
        else if (nData < pFind->nData)
        {
            pPre = &pFind->pLeftChild;
            pFind = pFind->pLeftChild;
        }
        else
        {
            pPre = &pFind->pRightChild;
            pFind = pFind->pRightChild;
        }

    }
    if (NULL == pFind)
    {
        return false;    
    }
    /******分四種情況******/
    //1、如果要刪除的節點沒有子節點
    if (pFind->pLeftChild == NULL && pFind->pRightChild == NULL)
    {
        //直接刪除該節點
        delete pFind;
       --m_nSize;//節點數減1
        //將指向該節點的指針置空
       *pPre = NULL;
        return true;
    }

    //2、如果要刪除的節點只有左孩子節點
    if (NULL != pFind->pLeftChild && NULL == pFind->pRightChild)
    {
        //被刪除節點的雙親節點重新指向被刪除節點的左孩子節點
        *pPre = pFind->pLeftChild;
        //刪除節點
        delete pFind;
        --m_nSize;//節點數減1
        return true;
    }

    //3、如果要刪除的節點只有右孩子節點
    if (NULL == pFind->pLeftChild && NULL != pFind->pRightChild)
    {
        //被刪除節點的雙親節點重新指向被刪除節點的右孩子節點
        *pPre = pFind->pRightChild;
        //刪除節點
        delete pFind;
        --m_nSize;//節點數減1
        return true;
    }

    //4、如果要刪除的節點有左右孩子節點
    if (NULL != pFind->pLeftChild && NULL != pFind->pRightChild)
    {
        //找出關鍵字值大於被刪除節點的關鍵字值中的最小值,即尋找被刪除節點右子樹中的最左值
        Node *pTarget = pFind->pRightChild;//最左值的指針
        Node *pNext = pFind->pRightChild;
        while(NULL != pNext)
        {
            pTarget = pNext;
            pNext = pTarget->pLeftChild;
        }
        //交換最左節點和被刪除節點的值
        pFind->nData = pTarget->nData;
        //以被刪除節點的右節點爲根節點,最左節點關鍵字的值爲刪除目標,再次調用刪除函數
        return Erase(&pFind->pRightChild, pTarget->nData);   
    }

}

void BinSortTree::Traversal(int nType)
{
    if (0 == nType)
    {
        //中序遍歷二叉樹
        InorderTraversal(m_pRoot);
    }
    else if (1 == nType)
    {
        LevelOrderTraversal(m_pRoot);
    }

}

void BinSortTree::InorderTraversal(Node *pNode)
{

    if (pNode == NULL)
    {
        return;
    }
    //先遍歷左子樹
    if (NULL != pNode->pLeftChild)
    {
        InorderTraversal(pNode->pLeftChild);
    }
    //訪問根節點
    cout << pNode->nData << endl;
    //遍歷右子樹
    if (NULL != pNode->pRightChild)
    {

        InorderTraversal(pNode->pRightChild);
    }

}

//層序遍歷二叉樹
void BinSortTree::LevelOrderTraversal(Node *pNode)
{
    if (pNode == NULL)
    {
        return;
    }
    //層序遍歷需要一個隊列保存未訪問節點,按從根層到底層的順序邊淋(從上到下,從左到右)
    queue<Node*> que;
    que.push(pNode);

    while (!que.empty())
    {
        //訪問節點
        Node *p = que.front();
        que.pop();//出隊列
        cout << p->nData << endl;//訪問節點

        if (NULL != p->pLeftChild)
        {
            que.push(p->pLeftChild);
        }
        if (NULL != p->pRightChild)
        {
            que.push(p->pRightChild);
        }
    }
}

main.cpp

#include <iostream>
#include "BinSortTree.h"
using namespace std;

int main()
{
BinSortTree tree;
tree.Insert(10);
tree.Insert(1);
tree.Insert(11);
tree.Insert(11);
tree.Insert(-1);
tree.Insert(99);

cout << "*************中序遍歷二叉樹(刪除前)**********" << endl;
tree.Traversal();

tree.Erase(10);
Node *pNode = tree.Find(10);
if (NULL != pNode)
{
  cout << "找到節點:" << pNode->nData << endl;
}
cout << "*************中序遍歷二叉樹(刪除後)**********" << endl;
tree.Traversal();

//cout << "*************層序遍歷二叉樹**********" << endl;
//tree.Traversal(1);
return 0; 
}


 

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