二叉搜索树之红黑树

红黑树首先是一棵二叉查找树,它每个结点都被标上了颜色(红色或黑色),红黑树满足以下5个性质:

1、 每个结点的颜色只能是红色或黑色。
2、 根结点是黑色的。
3、每个叶子结点都带有两个空的黑色结点(被称为黑哨兵),如果一个结点n的只有一个左孩子,那么n的右孩子是一个黑哨兵;如果结点n只有一个右孩子,那么n的左孩子是一个黑哨兵。
4、 如果一个结点是红的,则它的两个儿子都是黑的。也就是说在一条路径上不能出现相邻的两个红色结点。
5、对于每个结点来说,从该结点到其子孙叶结点的所有路径上包含相同数目的黑结点。

这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。

要知道为什么这些特性确保了这个结果,注意到性质4导致了路径不能有两个毗连的红色节点就足够了。最短的可能路径都是黑色节点,最长的可能路径有交替的红色和黑色节点。因为根据性质5所有最长的路径都有相同数目的黑色节点,这就表明了没有路径能多于任何其他路径的两倍长。

红黑树上结点的插入

注意:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点

【情况一】 cur为红,p为红,g为黑,u存在且为红 则将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。

这里写图片描述

【情况二】 cur为红,p为红,g为黑,u不存在/u为黑
p为g的左孩子,cur为p的左孩子,则进行右单旋转;相反,p为g的右孩子,cur为p的右孩子,则进行左单旋转
p、g变色–p变黑,g变红

这里写图片描述

【情况三】 cur为红,p为红,g为黑,u不存在/u为黑
p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;相
反,p为g的右孩子,cur为p的左孩子,则针对p做右单旋转 则转换成了情况2

这里写图片描述

代码如下:

#include<iostream>
using namespace std;

enum COLOR{RED, BLACK};

template<class K, class V>
struct RBTreeNode
{
    RBTreeNode(const K& key, const V& value, 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;
};


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, BLACK);
            return true;
        }
        //找插入位置
        Node* pCur = _pRoot;
        Node* parent = NULL;
        while(pCur)
        {
            if(key > pCur->_key)
            {
                parent = pCur;
                pCur = pCur->_pRight;
            }

            else if(key < pCur->_key)
            {
                parent = pCur;
                pCur = pCur->_pLeft;
            }

            else
                return false;
        }
        //插入节点
        pCur = new Node(key, value);
        if(key > parent->_key)
            parent->_pRight = pCur;
        else
            parent->_pLeft = pCur;

        pCur->_pParent = parent;

        Node* pGrangFather = parent->_pParent;
        有可能违反红黑树性质
        while(pCur != _pRoot && parent->_color == RED)
        {
            //双亲的双亲一定存在,且为黑色
            if(parent == pGrangFather->_pLeft)
            {
                Node* pUncle = pGrangFather->_pRight;
                //情况一:pCur为红色,parent为红色,grand为黑色,uncle为红色
                if(pUncle && pUncle->_color == RED )
                    //uncle存在且为红
                {
                    parent->_color = BLACK;
                    pUncle->_color = BLACK;
                    pGrangFather->_color = RED;

                    pCur = pGrangFather;
                    parent = pGrangFather->_pParent;
                }
                //uncle不存在或者uncle存在且为黑色
                else
                {
                    //情况三:pCur为parent的右孩子
                    if(parent->_pRight == pCur)
                    {
                        _RotateL(parent);
                        swap(pCur, parent);
                    }

                    //情况二:pCur为parent的左孩子
                    parent->_color = BLACK;
                    pGrangFather->_color = RED;
                    _RotateR(pGrangFather);
                }
            }
            else
            {
                Node* pUncle = pGrangFather->_pLeft;
                //情况一:uncle存在而且uncle为红色
                if(pUncle && pUncle->_color == RED)
                {
                    parent->_color = BLACK;
                    pUncle->_color = BLACK;
                    pGrangFather->_color = RED;

                    pCur = pGrangFather;
                    parent = pGrangFather->_pParent;
                }
                //uncle不存在或者uncle存在且为黑色
                else
                {
                    //情况三:pCur为parent的左孩子
                    if(pCur == parent->_pLeft)
                    {
                        _RotateR(parent);
                        swap(parent, pCur);
                    }

                    //情况二:pCur为parent的左孩子
                    parent->_color = BLACK;
                    pGrangFather->_color = RED;
                    _RotateL(pGrangFather);
                }
            }
        }
        _pRoot->_color = BLACK;
        return true;
    }

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

    bool CheckRBTree()
    {
        //判断是否满足红黑树
        if(_pRoot == NULL)
            return true;

        if(_pRoot->_color == RED)
        {
            cout<<"根结点是红色的,不满足性质二"<<endl;
            return false;
        }

        size_t count = 0;
        Node* pCur = _pRoot;
        while (pCur)
        {
            if (pCur->_color == BLACK)
                count++;
            pCur = pCur->_pLeft;
        }//统计最左边路径上得黑色结点数

        size_t num = 0;

        return CheckColour(_pRoot) && _CheckRBTree(_pRoot, count, num);
    }


    bool CheckColour(Node* pRoot)
    {//检查颜色
        if (pRoot)
            return true;

        Node* parent = pRoot->_pParent;
        if (pRoot->_color == RED && parent->_color == RED)
        {
            cout<<"有两个连续的红色节点数,不满足性质3"<<endl;
            return false;
        }

        return CheckColour(pRoot->_pLeft) && CheckColour(pRoot->_pRight);
    }

protected:
    void _RotateL(Node* parent)
    {
        Node* pSubR = parent->_pRight;
        Node* pSubRL = pSubR->_pLeft;

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

        pSubR->_pLeft = parent;
        Node* pparent = parent->_pParent;
        parent->_pParent = pSubR;
        pSubR->_pParent = pparent;

        if(pparent == NULL)
            _pRoot = pSubR;
        else
        {
            if(parent == pparent->_pLeft)
                pparent->_pLeft = pSubR;
            else
                pparent->_pRight = pSubR;
        }
    }

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

        parent->_pLeft = pSubLR;
        if(pSubLR)
            pSubLR->_pParent = parent;
        pSubL->_pRight = parent;
        Node* pparent = parent->_pParent;
        parent->_pParent = pSubL;
        pSubL->_pParent = pparent;
        if(pparent == NULL)
            _pRoot = pSubL;
        else
        {
            if(parent == pparent->_pLeft)
                pparent->_pLeft = pSubL;
            else
                pparent->_pRight = pSubL;
        }
    }

    void _InOrder(Node* pRoot)
    {
        if(pRoot)
        {
            _InOrder(pRoot->_pLeft);
            cout<<pRoot->_key<<" ";
            _InOrder(pRoot->_pRight);
        }
    }

    bool _CheckRBTree(Node* pRoot, const size_t blackCount, size_t k)
    {
        //检查黑色结点数目
        if (pRoot == NULL)
            return true;

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

        if (pRoot->_pLeft == NULL && pRoot->_pRight == NULL && blackCount != k)
        {
            cout<<"每条路径上的黑色节点数不相等,不满足性质4"<<endl;
            return false;
        }

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

protected:
    Node* _pRoot;
};

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();

    t.CheckRBTree();
}

int main()
{
    TestRBTree();

    system("pause");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值