二叉搜索樹---紅黑樹節點插入

1.紅黑樹的概念:紅黑樹是一棵二叉搜索樹,它在每個節點上增加一個存儲位來表示節點的顏色,可以是red或black,通過對任何一條從根節點到葉子節點上的間單路徑來約束,紅黑樹保證最長路徑不超過最短路徑的兩倍,因而近視平衡。

2.紅黑樹的性質

  • 性質1,每個節點不是黑色就是紅色
  • 性質2,根節點是黑色的;
  • 性質3,如果一個根節點是紅色的,則它的兩個葉子節點是紅色的,即沒有兩個連續節點是紅色節點
  • 性質4,對於每一個節點,從該節點到其所有後代葉節點的簡單路徑上,均包含相同數目的黑色節點,即每條路徑上黑色節點的個數是相等的;
  • 性質5,每個節點其空指針域是顏色的黑色的

滿足上訴性質的二叉搜索樹是二叉搜索樹

3.具體插入節點的步驟:
這裏寫圖片描述

對於插入節點的雙親節點是紅色時,我們又分爲三種情況對其調整

  • 情況1
    這裏寫圖片描述

  • 情況2
    這裏寫圖片描述

  • 情況3
    這裏寫圖片描述

4.根據上述的五種情況,實現代碼

#include<stdio.h>
#include<iostream>
using namespace std;

enum COLOR{RED,BLACK,};

template<class k,class v>
struct RBTreeNode
{
    RBTreeNode(const k& key,const v& value,COLOR color = RED)
        :_pLeft(NULL)
        ,_pRight(NULL)
        ,_pParent(NULL)
        ,_key(key)
        ,_value(value)
        ,_color(color)
    {}

    RBTreeNode<k,v>* _pLeft;
    RBTreeNode<k,v>* _pRight;
    RBTreeNode<k,v>* _pParent;
    k _key;
    v _value;
    COLOR _color;
};
template<class k,class v>
class RBTree
{
public:
    typedef RBTreeNode<k,v> Node;
    RBTree()
        :_pRoot(NULL)
    {}

    bool Insert(const k& key,const v& value)
    {
        return _Insert(key,value);
    }

    void InOrder()
    {
        cout<<"InOrder: ";
        _InOrder(_pRoot);
        cout<<endl;
    }

    bool CheckRBTree()
    {
        if(_pRoot == NULL)
            return true;
        if(_pRoot->_pLeft == NULL && _pRoot->_pRight == NULL)
        {
            if(_pRoot->_color == BLACK)
                return true;
            else
                return false;
        }

        int blackcount = 0;
        Node* pCur = _pRoot;
        while(pCur)
        {
            if(pCur->_color == BLACK)
                blackcount++;
            pCur= pCur->_pLeft;
        }

        int k = 0;
        return _CheckRBTree(_pRoot,blackcount,k);
    }

private:
    bool _CheckRBTree(Node* pRoot,int blackcount,int k)
    {
        if(pRoot == NULL)
            return true;
        if(pRoot->_color == BLACK)
            ++k;
        Node* pParent = pRoot->_pParent;
        if(pParent && pParent->_color == RED && pRoot->_color == RED)
        {
            cout<<"紅色節點相鄰,違反了性質3"<<endl;
            return false;
        }
        if(pRoot->_pLeft == NULL && pRoot->_pRight == NULL)
        {
            if(k != blackcount)
            {
                cout<<"每條路徑的黑色節點個數不同,違反了性質4"<<endl;
                return false;
            }
        }
        return _CheckRBTree(pRoot->_pLeft,blackcount,k)&&_CheckRBTree(pRoot->_pRight,blackcount,k);
    }
    void _InOrder(Node* pRoot)
    {
        if(pRoot == NULL)
            return;
        _InOrder(pRoot->_pLeft);
        cout<<pRoot->_key<<" ";
        _InOrder(pRoot->_pRight);
    }
    bool _Insert(const k& key,const v& value)
    {
        if(_pRoot == NULL)
        {
            _pRoot = new Node(key,value,BLACK);
            return true;
        }
        //找到要節點刪除的位置
        Node* pNode = _pRoot;
        Node* pParent = NULL;
        while(pNode)
        {
            if(pNode->_key > key)
            {
                pParent = pNode;
                pNode = pNode->_pLeft;
            }
            else if(pNode->_key < key)
            {
                pParent = pNode;
                pNode = pNode->_pRight;
            }
            else 
            {
                return false;//找到key值節點,不用插入,直接退出
            }
        }

        //已經找到
        pNode = new Node(key,value);
        if(pParent->_key > key)
        {
            pParent->_pLeft = pNode;
            pNode->_pParent = pParent;
        }
        else
        {
            pParent->_pRight = pNode;
            pNode->_pParent = pParent;
        }

        //對紅黑樹進行調整


        while(pParent && pParent->_color == RED && pNode->_color == RED)
        {
            Node* grandFather = pParent->_pParent;
            Node* pUncle = NULL;

            ////找到pUncle節點
            //if(grandFather->_pLeft == pParent)
            //  pUncle = grandFather->_pRight;
            //else
            //  pUncle = grandFather->_pLeft;

            if(grandFather->_pLeft == pParent)//節點插在左子樹
            {
                pUncle = grandFather->_pRight;
                if(pUncle && pUncle->_color == RED)//情況一
                {
                    pUncle->_color = BLACK;
                    pParent->_color = BLACK;
                    grandFather->_color = RED;

                    pNode = grandFather;
                    pParent = grandFather->_pParent;

                }

                else//在處理情況三的過程中順便處理情況二
                {
                    if(pParent && pParent->_pRight == pNode)
                    {
                        //先左旋再右旋
                        _RotateL(pParent);
                        swap(pNode,pParent);
                    }
                    grandFather->_color = RED;
                    pParent->_color = BLACK;
                    _RotateR(grandFather);
                }
            }
            else
            {
                pUncle = grandFather->_pLeft;
                if(pUncle && pUncle->_color == RED)//情況一
                {
                    pUncle->_color = BLACK;
                    pParent->_color = BLACK;
                    grandFather->_color = RED;

                    pNode = grandFather;
                    pParent = grandFather->_pParent;


                }
                //在處理情況三的過程中順便處理情況二

                else
                {
                    if(pUncle && pUncle->_color == BLACK && pParent->_pLeft == pNode)//情況三
                    {
                        //先左旋再右旋
                        _RotateR(pParent);
                        swap(pNode,pParent);
                    }
                    grandFather->_color = RED;//情況二
                    pParent->_color = BLACK;
                    _RotateL(grandFather);
                }
            }
        }
        _pRoot->_color = BLACK;
    }

    void _RotateL(Node*& pParent)
    {
        Node* pSubR = pParent->_pRight;
        Node* pSubRL = pSubR->_pLeft;

        pParent->_pRight = pSubRL;
        if(pSubRL)
            pSubRL->_pParent = pParent;
        pSubR->_pLeft = pParent;
        Node* pPParent = pParent->_pParent;
        pParent->_pParent = pSubR;

        pSubR->_pParent = pPParent;
        if(pPParent == NULL)
            _pRoot = pSubR;
        else if(pPParent->_pLeft == pParent)
            pPParent->_pLeft = pSubR;
        else 
            pPParent->_pRight = pSubR;
    }

    void _RotateR(Node*& pParent)
    {
        Node* pSubL = pParent->_pLeft;
        Node* pSubLR = pSubL->_pRight;

        pParent->_pLeft = pSubLR;
        if(pSubLR)
            pSubLR->_pParent = pParent;
        pSubL->_pRight = pParent;
        Node* pPParent = pParent->_pParent;
        pParent->_pParent = pSubL;

        pSubL->_pParent = pPParent;
        if(pPParent==NULL)
            _pRoot = pSubL;
        else if(pPParent->_pLeft == pParent)
            pPParent->_pLeft = pSubL;
        else
            pPParent->_pRight = pSubL;
    }
private:
    Node* _pRoot;
};

測試代碼:

void funtest()
{
    RBTree<int ,int> rbt;
    int array[] = {40,30,60,10,50,80,20,70};
    for(size_t idx=0; idx<sizeof(array)/sizeof(array[0]); ++idx)
        rbt.Insert(array[idx],array[idx]);
    rbt.InOrder();
    if(rbt.CheckRBTree())
    {
        cout<<"該樹是紅黑樹"<<endl;
    }
    else
    {
        cout<<"該樹不是紅黑樹"<<endl;
    }

}

int main()
{
    funtest();
    getchar();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章