紅黑樹的實現 以及加迭代器

在說紅黑樹之前,我們先來認識一下它:

首先強調一點:紅黑樹也是二叉搜索樹。那麼它就滿足二叉搜索樹的性質,除此之外,他還有幾個比較特殊的性質,瞭解這些,有助於我們後面的分析

性質:

1、紅黑樹所有的節點都有顏色(紅或黑)

2、紅黑樹的根結點是黑色的

3、紅黑樹的兩個紅色節點不能相連

4、紅黑樹的每一條鏈的黑節點的個數相同

5、所有空的節點都是黑色的

知道了這些之後開始進入紅黑樹的創建:

顯然這就是紅黑樹的插入操作的編寫了,那麼要想將一個節點插入紅黑樹中,首先你得判斷紅黑樹是不是空的,如果是空的,那麼直接就可以插入;不是空的,那麼得找插入位置,然後再插入,這一點和二叉搜索樹的插入是一樣的。不過需要注意,最後把根結點置成黑色的

但是之後呢?

插入的節點我們都默認爲紅色的,但是性質3說,紅色的節點不能相鏈,如果,之後我們不管的話,性質3肯定不會滿足的,所以我們需要對紅黑樹進行調解,讓其滿足這些性質。那麼我們就需要分情況討論了,我們重點分析一下,兩個紅色節點相鏈的情況怎麼處理。

總共可以分爲3種情況:

情況一:

雙親結點爲紅色,祖先結點爲黑色, 叔叔節點存在,且爲紅色

這裏寫圖片描述

其實這個圖裏包含了四種情況,我只是將其中的一種情況中的轉化後的形式畫了出來,其他的也一樣。

情況二:

雙親結點爲紅色,祖先結點爲黑色,叔叔節點不存在或存在爲黑色

這裏寫圖片描述

這種情況是:雙親在祖先節點的左的同時pCur在雙親的左;或是雙親在祖先節點的右的同時,pCur在雙親的右。

這樣我們就可以進行單旋處理,根據情況調用左單旋還是右單旋。

情況三:

雙親結點爲紅色,祖先結點爲黑色,叔叔節點不存在或存在爲黑色

這裏寫圖片描述
這個和情況二是互補的,情況二中剩下的都是不能單旋直接處理的,那麼就需要雙旋,圖中畫的是左右雙旋,先左旋之後,我們發現,和情況二的一樣,那麼代碼中這一塊就可以放在一起處理。

不過,這裏需要注意一點,就是,左旋之後只想pCur變成了雙親,而parent變成了孩子,所以,在第一次旋轉之後先對這兩個指針進行交換,在進行第二次旋轉。

最後將插入寫完之後,我們可以寫一個函數來測試一下這個是不是紅黑樹,這個其實也是對紅黑樹的性質的檢驗。其中重點驗證性質3和性質4。那麼我們來分析一下這步驟:

1、判斷這個樹是不是空樹,是的話,直接返回true

2、驗證性質2,判斷根結點的顏色是不是黑色的,是,返回true

3、要驗證性質三,得遍歷整個樹,而性質4的驗證也要這莫做,那麼我們將這兩個一起驗證。那麼首先我們得求出一條鏈的黑色節點的個數,並將其保存起來,再遞歸遍歷左右子樹,驗證。

//無迭代器
template<class K, class V>
class RBTree
{
    typedef RBTreeNode<K, V> Node;
public:
    RBTree()
        :_pRoot(NULL)
    {}
    // 首先:搜索樹
    bool Insert(const K& key, const V& value)
    {
        if (_pRoot == NULL)
        {
            _pRoot = new Node(key, value);
            _pRoot->_color = BLACK;
            return true;
        }

        //找插入位置
        Node*pCur = _pRoot;
        Node*parent = NULL;
        while (pCur)
        {
            if (key < pCur->_key)
            {
                parent = pCur;
                pCur = pCur->_pLeft;
            }
            else if (key>pCur->_key)
            {
                parent = pCur;
                pCur = pCur->_pRight;
            }
            else
                return false;
        }

        //插入
        pCur = new Node(key, value);
        if (key < parent->_key)
            parent->_pLeft = pCur;
        else
            parent->_pRight = pCur;

        pCur->_pParent = parent;//注意,不要遺漏了。。。

        //看紅黑樹是否還滿足其性質(分情況討論)
        while (_pRoot!=pCur && pCur->_pParent->_color == RED)
        {
            Node* gf = parent->_pParent;//保存雙親的雙親
            //gf肯定存在,因爲,如果不存在,那麼parent就是根結點,是黑色的,不會進入這個循環

            //雙親在左,叔叔(存在的話)在右
            if (gf->_pLeft == parent)
            {
                Node*uncle = gf->_pRight;
                if (uncle && uncle->_color == RED)  //情況一
                {
                    parent->_color = BLACK;
                    uncle->_color = BLACK;
                    gf->_color = RED;

                    //向上更新
                    pCur = gf;
                    parent = pCur->_pParent;
                }
                else   //情況二、三(將情況三轉化爲情況二,再一起處理)
                {
                    if (parent->_pRight == pCur)
                    {
                        _RotateL(parent);
                        std::swap(parent, pCur);
                    }

                    gf->_color = RED;
                    parent->_color = BLACK;
                    _RotateR(gf);
                }
            }
            else//雙親在右
            {
                Node*uncle = gf->_pLeft;
                if (uncle && uncle->_color == RED)  //情況一
                {
                    parent->_color = BLACK;
                    uncle->_color = BLACK;
                    gf->_color = RED;

                    //向上更新
                    pCur = gf;
                    parent = pCur->_pParent;
                }
                else   //情況二、三(將情況三轉化爲情況二,再一起處理)
                {
                    if (parent->_pLeft == pCur)
                    {
                        _RotateR(parent);
                        std::swap(parent, pCur);
                    }

                    gf->_color = RED;
                    parent->_color = BLACK;
                    _RotateL(gf);
                }
            }
        }
        _pRoot->_color = BLACK;
        return true;
    }

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

    //判斷是不是紅黑樹
    bool CheckRBTree()
    {       
        if (_pRoot == NULL)
            return true;

        if (_pRoot->_color == RED)//違反性質2“根結點爲黑色”
            return false;

        size_t blackcount = 0;//統計一條鏈中黑色結點的數量

        Node* pCur = _pRoot;
        while (pCur)
        {
            if (pCur->_color == BLACK)
                blackcount++;
            pCur = pCur->_pLeft;//這裏以最左邊的那一條鏈爲例
        }

        //驗證性質4“每條鏈上的黑色結點都相等”,順便驗證性質3“紅色結點不能相連”
        return _CheckRBTree(_pRoot, blackcount, 0);
    }

private:

    //判斷是不是紅黑樹(遞歸)
    //k用來統計每一條鏈上的黑色結點的個數,但是不能給成引用,否則,再次統計下一條鏈的時候,就不會更新
    bool _CheckRBTree(Node* pRoot, const size_t blackCount, size_t k)
    {
        if (pRoot == NULL)
            return true;

        if (pRoot->_color == BLACK)
            k++;

        Node* parent = pRoot->_pParent;
        if (parent && parent->_color == RED && pRoot->_color == RED)//違反性質3
            return false;

        if (pRoot->_pLeft == NULL&&pRoot->_pRight == NULL)
        {
            if (k != blackCount)//違反性質4
                return false;
        }

        return _CheckRBTree(pRoot->_pLeft, blackCount, k)
            && _CheckRBTree(pRoot->_pRight, blackCount, k);
    }

    //左旋
    void _RotateL(Node* parent)
    {
        Node* subR = parent->_pRight;
        Node* subRL = subR->_pLeft;//有可能不存在

        parent->_pRight = subRL;
        if (subRL)
            subRL->_pParent = parent;

        subR->_pLeft = parent;
        Node* gparent = parent->_pParent;//保存parent的雙親
        parent->_pParent = subR;

        if (gparent == NULL)//parent是根結點
            _pRoot = subR;
        else if (gparent->_pLeft == parent)
            gparent->_pLeft = subR;
        else
            gparent->_pRight = subR;

        subR->_pParent = gparent;//第三個
    }

    //右旋
    void _RotateR(Node* parent)
    {
        Node*subL = parent->_pLeft;
        Node*subLR = subL->_pRight;

        parent->_pLeft = subLR;
        if (subLR)
            subL->_pParent = parent;

        subL->_pRight = parent;
        Node*gparent = parent->_pParent;
        parent->_pParent = subL;
        subL->_pParent = gparent;

        if (gparent == NULL)
            _pRoot = subL;
        else if (gparent->_pLeft == parent)
            gparent->_pLeft = subL;
        else
            gparent->_pRight = subL;
    }

    //中序遍歷
    void _InOrder(Node* pRoot)
    {
        if (pRoot)
        {
            _InOrder(pRoot->_pLeft);
            cout << pRoot->_key << " ";
            _InOrder(pRoot->_pRight);
        }
    }

    //獲取最小節點
    Node* _GetMinNode()
    {
        Node* pCur = _pRoot;
        Node*parent = NULL;
        while (pCur)
        {
            parent = pCur;
            pCur = pCur->_pLeft;
        }
        return parent;
    }

    //獲取最大節點
    Node* _GetMaxNode()
    {
        Node* pCur = _pRoot;
        Node*parent = NULL;
        while (pCur)
        {
            parent = pCur;
            pCur = pCur->_pRight;
        }
        return parent;
    }

private:
    Node* _pRoot;
};

#endif


void TestRBTree()
{
    int a[] = { 10, 7, 8, 15, 5, 6, 11, 13, 12 };
    RBTree<int, int> t;
    for (int idx = 0; idx < sizeof(a) / sizeof(a[0]); ++idx)
        t.Insert(a[idx], idx);

    t.InOrder(); 

    if (t.CheckRBTree())
    {
        cout << "是紅黑樹" << endl;
    }
    else
    {
        cout << "不是紅黑樹" << endl;
    }
}

迭代器中給出了什麼操作:

Self& operator++();
Self operator++(int);
Self& operator--();
Self operator--(int);
Ref operator*();//這裏的Ref是我自己通過模板類給出的類型
const Ref operator*()const ;
Pointer operator->();
const Pointer operator->()const;

這裏重點就是自增和自減的操作,我們知道紅黑是是二叉搜索樹,那麼他的中序遍歷是有序的,所以,在迭代器下,一個節點的下一個節點是它右子樹的最左邊的節點;同樣,一個節點的上一個節點是他左子樹的最右邊的節點。

但是這裏總有一些例外的情況,如:一個結點右子樹沒有左節點那麼怎麼處理,或是左子樹沒有右節點呢?

這裏寫圖片描述

這裏寫圖片描述

對於這兩種情況我們需要特別處理,那麼以第二個圖來說,這是右子樹沒有左節點的情況,也就是自增的情況,那麼我們需要將其雙親保存起來,然後向上面遍歷們直到找到一個其左孩子存在爲止,這時候,其就是要找的節點。

同樣的,自減也是這樣,不過這裏需要要遭注意一個特殊的地方,就是,在頭結點的位置,我們要是進行自減的話,按理說,應該是到key最大的位置,但是,我們的代碼中,並不適用這個,所以,我們需要拿出來單獨處理。

 void _Increment()
    {
        //找右子樹的最左邊的節點
        if (_pNode->_pRight)
        {
            _pNode = _pNode->_pRight;
            while (_pNode->_pLeft)
                _pNode = _pNode->_pLeft;
        }

        //特殊情況
        else
        {
            Node* parent = _pNode->_pParent;
            while (parent->_pRight == _pNode)
            {
                _pNode = parent;
                parent = parent->_pParent;
            }
            if (parent->_pRight != _pNode)
                _pNode = parent;
        }
    }

    void _Decrement()
    {
        //頭結點的情況:自減之後到key最大的結點
        if (_pNode->_color == RED&&_pNode->_pParent->_pParent == _pNode)
            _pNode = _pNode->_pRight;

        //找左子樹的最右邊的節點
        else if (_pNode->_pLeft)
        {
            _pNode = _pNode->_pLeft;
            while (_pNode->_pRight)
                _pNode = _pNode->_pRight;
        }

        //特殊情況處理
        else
        {
            Node* parent = _pNode->_pParent;
            while (parent->_pLeft == _pNode)
            {
                _pNode = parent;
                parent = parent->_pParent;
            }
            _pNode = parent;
        }
    }

下面是完整的代碼:

#include<iostream>
using namespace std;


enum COLOR{ RED, BLACK };

template<class K, class V>
struct RBTreeNode
{
    RBTreeNode(const K& key = K(), const V& value = V(), const 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;  //結點的顏色,初始值爲紅色
};

#if 0
template<class K, class V, class Ref, class Pointer>
class RBTreeIterator
{
    typedef RBTreeNode<K, V> Node;
    typedef RBTreeIterator<K, V, Ref, Pointer> Self;
public:
    RBTreeIterator()
        : _pNode(NULL)
    {}

    RBTreeIterator(Node* pNode)
        : _pNode(pNode)
    {}

    RBTreeIterator(RBTreeIterator& it)
        : _pNode(it._pNode)
    {}

    Self& operator++()
    {
        _Increment();
        return *this;
    }

    Self operator++(int)
    {
        Self temp = *this;
        _Increment();
        return temp;
    }

    Self& operator--()
    {
        _Decrement();
        return *this;
    }

    Self operator--(int)
    {
        Self temp = *this;
        _Decrement();
        return temp;
    }

    Ref operator*()
    {
        return _pNode->_key;
    }

    const Ref operator*()const
    {
        return _pNode->_key;
    }

    Pointer operator->()
    {
        return &(operator*());
    }

    const Pointer operator->()const
    {
        return &(operator*());
    }

    bool operator==(const Self& it)
    {
        return _pNode == it._pNode;
    }

    bool operator!=(const Self& it)
    {
        return _pNode != it._pNode;
    }

protected:
    void _Increment()
    {
        //找右子樹的最左邊的節點
        if (_pNode->_pRight)
        {
            _pNode = _pNode->_pRight;
            while (_pNode->_pLeft)
                _pNode = _pNode->_pLeft;
        }

        //特殊情況
        else
        {
            Node* parent = _pNode->_pParent;
            while (parent->_pRight == _pNode)
            {
                _pNode = parent;
                parent = parent->_pParent;
            }
            if (parent->_pRight != _pNode)
                _pNode = parent;
        }
    }

    void _Decrement()
    {
        //頭結點的情況:自減之後到key最大的結點
        if (_pNode->_color == RED&&_pNode->_pParent->_pParent == _pNode)
            _pNode = _pNode->_pRight;

        //找左子樹的最右邊的節點
        else if (_pNode->_pLeft)
        {
            _pNode = _pNode->_pLeft;
            while (_pNode->_pRight)
                _pNode = _pNode->_pRight;
        }

        //特殊情況處理
        else
        {
            Node* parent = _pNode->_pParent;
            while (parent->_pLeft == _pNode)
            {
                _pNode = parent;
                parent = parent->_pParent;
            }
            _pNode = parent;
        }
    }

protected:
    Node* _pNode;
};


template<class K, class V>
class RBTree
{
    typedef RBTreeNode<K, V> Node;

public:
    typedef RBTreeIterator<K, V, K&, K*> Iterator;
public:
    RBTree()
        :_size(0)
    {
        _pHead = new Node(K(), V());
        _pHead->_pLeft = _pHead;
        _pHead->_pRight = _pHead;
        _pHead->_pParent = NULL;
        _pHead->_color = RED;
    }

    Iterator Begin()
    {
        return Iterator(_pHead->_pLeft);
    }

    Iterator End()
    {
        return Iterator(_pHead);//注意end的位置,不是最大的key所在結點
    }

    bool Empty()const
    {
        return _size == 0;
    }

    size_t Size()const
    {
        return _size;
    }

    Iterator Find(const K& key)
    {
        Iterator it = Begin();
        while (it != End())
        {
            if (key == *it)
                return it;
            else
                ++it;
        }
    }

    // 首先:搜索樹
    bool Insert(const K& key, const V& value)
    {
        Node* pRoot = _GetRoot();
        if (pRoot == NULL)
        {
            Node* pRoot = new Node(key, value);
            pRoot->_pParent = _pHead;
            _pHead->_pParent = pRoot;
            pRoot->_color = BLACK;
            _size++;
            return true;
        }

        //找插入位置
        Node*pCur = pRoot;
        Node*parent = NULL;
        while (pCur)
        {
            if (key < pCur->_key)
            {
                parent = pCur;
                pCur = pCur->_pLeft;
            }
            else if (key>pCur->_key)
            {
                parent = pCur;
                pCur = pCur->_pRight;
            }
            else
                return false;
        }

        //插入
        pCur = new Node(key, value);
        if (key < parent->_key)
            parent->_pLeft = pCur;
        else
            parent->_pRight = pCur;

        _size++;
        pCur->_pParent = parent;//注意,不要遺漏了。。。

        //看紅黑樹是否還滿足其性質(分情況討論)
        while (pRoot != pCur && parent->_color == RED)//這個條件很重要
        {
            Node* gf = parent->_pParent;//保存雙親的雙親

            //雙親在左,叔叔(存在的話)在右
            if (gf->_pLeft == parent)
            {
                Node*uncle = gf->_pRight;
                if (uncle && uncle->_color == RED)  //情況一
                {
                    parent->_color = BLACK;
                    uncle->_color = BLACK;
                    gf->_color = RED;

                    //向上更新
                    pCur = gf;
                    parent = pCur->_pParent;
                }
                else   //情況二、三(將情況三轉化爲情況二,再一起處理)
                {
                    if (parent->_pRight == pCur)
                    {
                        _RotateL(parent);
                        std::swap(parent, pCur);
                    }

                    gf->_color = RED;
                    parent->_color = BLACK;
                    _RotateR(gf);
                }
            }
            else//雙親在右
            {
                Node*uncle = gf->_pLeft;
                if (uncle && uncle->_color == RED)  //情況一
                {
                    parent->_color = BLACK;
                    uncle->_color = BLACK;
                    gf->_color = RED;

                    //向上更新
                    pCur = gf;
                    parent = pCur->_pParent;
                }
                else   //情況二、三(將情況三轉化爲情況二,再一起處理)
                {
                    if (parent->_pLeft == pCur)
                    {
                        _RotateR(parent);
                        std::swap(parent, pCur);
                    }

                    gf->_color = RED;
                    parent->_color = BLACK;
                    _RotateL(gf);
                }
            }
        }
        pRoot = _GetRoot();//旋轉完成之後要再把根結點獲取一遍

        pRoot->_color = BLACK;
        _pHead->_pLeft = _GetMinNode();
        _pHead->_pRight = _GetMaxNode();
        return true;
    }

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

    //判斷是不是紅黑樹
    bool CheckRBTree()
    {
        Node* pRoot = _GetRoot();
        if (pRoot == NULL)
            return true;

        if (pRoot->_color == RED)//違反性質2“根結點爲黑色”
            return false;

        size_t blackcount = 0;//統計一條鏈中黑色結點的數量

        while (pRoot)
        {
            if (pRoot->_color == BLACK)
                blackcount++;
            pRoot = pRoot->_pLeft;//這裏以最左邊的那一條鏈爲例
        }

        //驗證性質4“每條鏈上的黑色結點都相等”,順便驗證性質3“紅色結點不能相連”
        return _CheckRBTree(pRoot, blackcount, 0);
    }

private:

    //判斷是不是紅黑樹(遞歸)
    //k用來統計每一條鏈上的黑色結點的個數,但是不能給成引用,否則,再次統計下一條鏈的時候,就不會更新
    bool _CheckRBTree(Node* pRoot, const size_t blackCount, size_t k)
    {
        if (pRoot == NULL)
            return true;

        if (pRoot->_color == BLACK)
            k++;

        Node* parent = pRoot->_pParent;
        if (parent && parent->_color == RED && pRoot->_color == RED)//違反性質3
            return false;

        if (pRoot->_pLeft == NULL&&pRoot->_pRight == NULL)
        {
            if (k != blackCount)//違反性質4
                return false;
        }

        return _CheckRBTree(pRoot->_pLeft, blackCount, k)
            && _CheckRBTree(pRoot->_pRight, blackCount, k);
    }

    //左旋
    void _RotateL(Node* parent)
    {
        Node* subR = parent->_pRight;
        Node* subRL = subR->_pLeft;//有可能不存在

        parent->_pRight = subRL;
        if (subRL)
            subRL->_pParent = parent;

        subR->_pLeft = parent;
        Node* gparent = parent->_pParent;//保存parent的雙親
        parent->_pParent = subR;

        if (gparent == _pHead)//parent是根結點
        {
            _pHead->_pParent = subR;    //注意:這一塊的根結點怎麼表示
            subR->_pParent = _pHead;
        }
        else if (gparent->_pLeft == parent)
            gparent->_pLeft = subR;
        else
            gparent->_pRight = subR;

        subR->_pParent = gparent;//第三個
    }

    //右旋
    void _RotateR(Node* parent)
    {
        Node*subL = parent->_pLeft;
        Node*subLR = subL->_pRight;

        parent->_pLeft = subLR;
        if (subLR)
            subL->_pParent = parent;

        subL->_pRight = parent;
        Node*gparent = parent->_pParent;
        parent->_pParent = subL;
        subL->_pParent = gparent;

        if (gparent == _pHead)
        {
            _pHead->_pParent = subL;
            subL->_pParent = _pHead;
        }
        else if (gparent->_pLeft == parent)
            gparent->_pLeft = subL;
        else
            gparent->_pRight = subL;
    }

    //中序遍歷
    void _InOrder(Node* pRoot)
    {
        if (pRoot)
        {
            _InOrder(pRoot->_pLeft);
            cout << pRoot->_key << " ";
            _InOrder(pRoot->_pRight);
        }
    }

    //獲取根結點
    Node* &_GetRoot()
    {
        return _pHead->_pParent;
    }

    //獲取最小節點
    Node* _GetMinNode()
    {
        Node*pRoot = _pHead->_pParent;
        Node*parent = NULL;
        while (pRoot)
        {
            parent = pRoot;
            pRoot = pRoot->_pLeft;
        }
        return parent;
    }

    //獲取最大節點
    Node* _GetMaxNode()
    {
        Node*pRoot = _pHead->_pParent;
        Node*parent = NULL;
        while (pRoot)
        {
            parent = pRoot;
            pRoot = pRoot->_pRight;
        }
        return parent;
    }

private:
    Node* _pHead;  //頭結點
    size_t _size;  
};

#else

//無迭代器
template<class K, class V>
class RBTree
{
    typedef RBTreeNode<K, V> Node;
public:
    RBTree()
        :_pRoot(NULL)
    {}
    // 首先:搜索樹
    bool Insert(const K& key, const V& value)
    {
        if (_pRoot == NULL)
        {
            _pRoot = new Node(key, value);
            _pRoot->_color = BLACK;
            return true;
        }

        //找插入位置
        Node*pCur = _pRoot;
        Node*parent = NULL;
        while (pCur)
        {
            if (key < pCur->_key)
            {
                parent = pCur;
                pCur = pCur->_pLeft;
            }
            else if (key>pCur->_key)
            {
                parent = pCur;
                pCur = pCur->_pRight;
            }
            else
                return false;
        }

        //插入
        pCur = new Node(key, value);
        if (key < parent->_key)
            parent->_pLeft = pCur;
        else
            parent->_pRight = pCur;

        pCur->_pParent = parent;//注意,不要遺漏了。。。

        //看紅黑樹是否還滿足其性質(分情況討論)
        while (_pRoot!=pCur && pCur->_pParent->_color == RED)
        {
            Node* gf = parent->_pParent;//保存雙親的雙親
            //gf肯定存在,因爲,如果不存在,那麼parent就是根結點,是黑色的,不會進入這個循環

            //雙親在左,叔叔(存在的話)在右
            if (gf->_pLeft == parent)
            {
                Node*uncle = gf->_pRight;
                if (uncle && uncle->_color == RED)  //情況一
                {
                    parent->_color = BLACK;
                    uncle->_color = BLACK;
                    gf->_color = RED;

                    //向上更新
                    pCur = gf;
                    parent = pCur->_pParent;
                }
                else   //情況二、三(將情況三轉化爲情況二,再一起處理)
                {
                    if (parent->_pRight == pCur)
                    {
                        _RotateL(parent);
                        std::swap(parent, pCur);
                    }

                    gf->_color = RED;
                    parent->_color = BLACK;
                    _RotateR(gf);
                }
            }
            else//雙親在右
            {
                Node*uncle = gf->_pLeft;
                if (uncle && uncle->_color == RED)  //情況一
                {
                    parent->_color = BLACK;
                    uncle->_color = BLACK;
                    gf->_color = RED;

                    //向上更新
                    pCur = gf;
                    parent = pCur->_pParent;
                }
                else   //情況二、三(將情況三轉化爲情況二,再一起處理)
                {
                    if (parent->_pLeft == pCur)
                    {
                        _RotateR(parent);
                        std::swap(parent, pCur);
                    }

                    gf->_color = RED;
                    parent->_color = BLACK;
                    _RotateL(gf);
                }
            }
        }
        _pRoot->_color = BLACK;
        return true;
    }

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

    //判斷是不是紅黑樹
    bool CheckRBTree()
    {       
        if (_pRoot == NULL)
            return true;

        if (_pRoot->_color == RED)//違反性質2“根結點爲黑色”
            return false;

        size_t blackcount = 0;//統計一條鏈中黑色結點的數量

        Node* pCur = _pRoot;
        while (pCur)
        {
            if (pCur->_color == BLACK)
                blackcount++;
            pCur = pCur->_pLeft;//這裏以最左邊的那一條鏈爲例
        }

        //驗證性質4“每條鏈上的黑色結點都相等”,順便驗證性質3“紅色結點不能相連”
        return _CheckRBTree(_pRoot, blackcount, 0);
    }

private:

    //判斷是不是紅黑樹(遞歸)
    //k用來統計每一條鏈上的黑色結點的個數,但是不能給成引用,否則,再次統計下一條鏈的時候,就不會更新
    bool _CheckRBTree(Node* pRoot, const size_t blackCount, size_t k)
    {
        if (pRoot == NULL)
            return true;

        if (pRoot->_color == BLACK)
            k++;

        Node* parent = pRoot->_pParent;
        if (parent && parent->_color == RED && pRoot->_color == RED)//違反性質3
            return false;

        if (pRoot->_pLeft == NULL&&pRoot->_pRight == NULL)
        {
            if (k != blackCount)//違反性質4
                return false;
        }

        return _CheckRBTree(pRoot->_pLeft, blackCount, k)
            && _CheckRBTree(pRoot->_pRight, blackCount, k);
    }

    //左旋
    void _RotateL(Node* parent)
    {
        Node* subR = parent->_pRight;
        Node* subRL = subR->_pLeft;//有可能不存在

        parent->_pRight = subRL;
        if (subRL)
            subRL->_pParent = parent;

        subR->_pLeft = parent;
        Node* gparent = parent->_pParent;//保存parent的雙親
        parent->_pParent = subR;

        if (gparent == NULL)//parent是根結點
            _pRoot = subR;
        else if (gparent->_pLeft == parent)
            gparent->_pLeft = subR;
        else
            gparent->_pRight = subR;

        subR->_pParent = gparent;//第三個
    }

    //右旋
    void _RotateR(Node* parent)
    {
        Node*subL = parent->_pLeft;
        Node*subLR = subL->_pRight;

        parent->_pLeft = subLR;
        if (subLR)
            subL->_pParent = parent;

        subL->_pRight = parent;
        Node*gparent = parent->_pParent;
        parent->_pParent = subL;
        subL->_pParent = gparent;

        if (gparent == NULL)
            _pRoot = subL;
        else if (gparent->_pLeft == parent)
            gparent->_pLeft = subL;
        else
            gparent->_pRight = subL;
    }

    //中序遍歷
    void _InOrder(Node* pRoot)
    {
        if (pRoot)
        {
            _InOrder(pRoot->_pLeft);
            cout << pRoot->_key << " ";
            _InOrder(pRoot->_pRight);
        }
    }

    //獲取最小節點
    Node* _GetMinNode()
    {
        Node* pCur = _pRoot;
        Node*parent = NULL;
        while (pCur)
        {
            parent = pCur;
            pCur = pCur->_pLeft;
        }
        return parent;
    }

    //獲取最大節點
    Node* _GetMaxNode()
    {
        Node* pCur = _pRoot;
        Node*parent = NULL;
        while (pCur)
        {
            parent = pCur;
            pCur = pCur->_pRight;
        }
        return parent;
    }

private:
    Node* _pRoot;
};

#endif


void TestRBTree()
{
    int a[] = { 10, 7, 8, 15, 5, 6, 11, 13, 12 };
    RBTree<int, int> t;
    for (int idx = 0; idx < sizeof(a) / sizeof(a[0]); ++idx)
        t.Insert(a[idx], idx);

    t.InOrder(); 

    if (t.CheckRBTree())
    {
        cout << "是紅黑樹" << endl;
    }
    else
    {
        cout << "不是紅黑樹" << endl;
    }
}

//void TestIterator()
//{
//  int a[] = { 10, 7, 8, 15, 5, 6, 11, 13, 12 };
//  RBTree<int, int> t;
//  for (int idx = 0; idx < sizeof(a) / sizeof(a[0]); ++idx)
//      t.Insert(a[idx], idx);
//  t.InOrder();
//
//  RBTree<int, int>::Iterator it = t.Begin();
//  while (it != t.End())
//  {
//      cout << *it << " ";
//      ++it;
//  }
//
//  RBTree<int, int>::Iterator itEnd = t.End();
//  --itEnd;
//  cout << *itEnd << endl;
//}


int main()
{
    TestRBTree();
    //TestIterator();
    return 0;
}
發佈了121 篇原創文章 · 獲贊 90 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章