C++数据结构之红黑树

        红黑树是对于二叉搜索树除了AVL数外的另一种改进,对节点引入额外的颜色变量,通过对颜色规则的控制,保证树的最长路径不超过最短路径的二倍

1.红黑树的规则

        1.所有节点的颜色不是红色就是黑色

        2.根节点为黑色

        3.红色节点的孩子节点不可为红色,也就是不能出现连续的红色节点

        4.每条路径(从根节点到空节点)的黑色节点数量保持一致

 2.红黑树查询的时间复杂度

     设最短路径高为h,则总节点数 n 满足 (2^h) - 1<= n < (2^2h)-1,h大致为2logn,即搜索的时间复杂度仍为o(logn)

3.红黑树的插入

        若插入的节点为根节点,则插入为黑色节点,其余插入为红色节点

        插入结点后向上对红黑树进行检查与调整

        若父节点是黑色节点,停止检查,插入完毕

        若父节点是红色节点,则主要看父亲的兄弟节点,也就是叔叔节点的情况

        1.只变色的情况

              插入或变化节点的叔叔节点存在且为红色,则仅需把父亲节点的父亲节点,即爷爷节点变为红色,将父亲和叔叔节点变为黑色,就像爷爷节点的黑色流动下来了一样,然后将爷爷节点作为变化的节点继续向上检测更新,若爷爷节点是根节点,将根节点再变回黑色,插入结束

            2.变化颜色 + 单旋的情况

              插入或变化的节点在父节点左侧,父节点在爷爷节点左侧,叔叔节点为黑或不存在,对爷爷节点右单旋

              插入或变化的节点在父节点右侧,父节点在爷爷节点右侧,叔叔节点为黑或不存在,对爷爷节点左单旋

        关于旋转不会的可以看我AVL树的博客:C++数据结构之二叉搜索树和AVL树-优快云博客

        3.变化颜色 + 双旋的情况

                 插入或变化的节点在父节点右侧,父节点在爷爷节点左侧,叔叔节点为黑或不存在,对爷爷节点左右双旋

                插入或变化的节点在父节点左侧,父节点在爷爷节点右侧,叔叔节点为黑或不存在,对爷爷节点右左双旋

        以上便是红黑树插入的三种情况

4.红黑树的代码实现

#include<iostream>
using namespace std;


enum Color
{
    red,
    black
};
template<class T>
struct RBTreeNode
{
    RBTreeNode(const T& data = T())
        : _pLeft(nullptr)
        , _pRight(nullptr)
        , _pParent(nullptr)
        , _data(data)
        , _col(red)
    {}

    RBTreeNode<T>* _pLeft;
    RBTreeNode<T>* _pRight;
    RBTreeNode<T>* _pParent;
    T _data;
    Color _col;
};







// 为方便构建,先注释掉head节点,以root节点为准

template<class T>
class RBTree
{
    typedef RBTreeNode<T> Node;
public:
    RBTree() :_pRoot(nullptr)
    {
        /*
        _pHead = new Node;
        _pHead->_pLeft = _pHead;
        _pHead->_pRight = _pHead;
        */
    }

    ~RBTree()
    {
        destoryTree(_pRoot);
    }


    // 在红黑树中插入值为data的节点,插入成功返回true,否则返回false
    // 注意:为了简单起见,本次实现红黑树不存储重复性元素
    bool Insert(const T& data)
    {
        //先按二叉搜索树逻辑插入
        if (_pRoot == nullptr)
        {
            _pRoot = new Node;
            _pRoot->_data = data;
            _pRoot->_col = black;
            return true;
        }


        Node* cur = _pRoot;//cur为节点插入位置
        Node* curParent = nullptr;

        while (cur->_data != data)
        {
            if (cur->_data > data)
            {
                curParent = cur;
                cur = curParent->_pLeft;
            }
            else
            {
                curParent = cur;
                cur = curParent->_pRight;
            }

            if (cur == nullptr)
            {
                //发现可插入位置,将新节点给cur,并插于curParent下,将curParent平衡因子更新
                cur = new Node;
                cur->_data = data;
                cur->_pParent = curParent;
                if (data < curParent->_data)
                {
                    curParent->_pLeft = cur;
                }
                else
                {
                    curParent->_pRight = cur;
                }
            }

        }
            //判断与父节点颜色是否匹配,若不匹配则进行平衡
            while (cur->_col == red && curParent->_col == red)
            {
                Node* curGurand = curParent->_pParent;
                Node* curUncle = nullptr;
                if (curGurand->_pLeft == curParent)
                {
                    curUncle = curGurand->_pRight;
                }
                else
                {
                    curUncle = curGurand->_pLeft;
                }

                //只改颜色的情况
                if (curUncle && curUncle->_col == red)
                {
                    curGurand->_col = red;
                    curParent->_col = black;
                    curUncle->_col = black;


                    if (curGurand == _pRoot)
                    {
                        curGurand->_col = black;
                        break;
                    }


                    //以祖父节点为源继续检测
                    cur = curGurand;
                    curParent = cur->_pParent;
                }

                //旋转的情况
                else
                {
                    if (curGurand->_pLeft == curParent)
                    {
                        if (curParent->_pLeft == cur)
                        {
                            //   g
                            //  p  u
                            // c
                            //右单旋
                            RotateR(curGurand);
                            curParent->_col = black;
                            curGurand->_col = red;
                            
                            break;

                        }
                        else
                        {
                            //   g
                            // p   u
                            //  c
                            //左右双旋
                            RotateLR(curGurand);
                            cur->_col = black;
                            curGurand->_col = red;

                            
                            break;
                        }
                    }
                    else
                    {
                        if (curParent->_pRight == cur)
                        {
                            //  g
                            //u   p
                            //      c
                            //左单旋
                            RotateL(curGurand);
                            curParent->_col = black;
                            curGurand->_col = red;
                            if (curGurand == _pRoot)
                            {
                                _pRoot = curParent;
                            }
                            break;
                        }
                        else
                        {
                            //  g
                            //u   p
                            //   c
                            //右左双旋
                            RotateRL(curGurand);
                            cur->_col = black;
                            curGurand->_col = red;
                            if (curGurand == _pRoot)
                            {
                                _pRoot = cur;
                            }
                            break;
                        }
                    }
                }

            

            return true;




        }

    }


    // 检测红黑树中是否存在值为data的节点,存在返回该节点的地址,否则返回nullptr
    Node* Find(const T& data)
    {
        Node* cur = _pRoot;
        while (cur)
        {
            if (cur->_data == data)
            {
                return cur;
            }
            else if (cur->_data > data)
            {
                cur = cur->_pLeft;
            }
            else
            {
                cur = cur->_pRight;
            }

        }

        return nullptr;

    }

    // 获取红黑树最左侧节点
    Node* LeftMost()
    {
        
        return _LeftMost(_pRoot);

    }

    // 获取红黑树最右侧节点
    Node* RightMost()
    {
        return _RightMost(_pRoot);
    }

    // 检测红黑树是否为有效的红黑树,注意:其内部主要依靠_IsValidRBTRee函数检测
    bool IsValidRBTRee()
    {
        rsize_t num = getBNum(_pRoot);
        return _IsValidRBTRee(_pRoot,0,num);
    }

    //展示树
    void showTree()
    {
        _showTree(_pRoot);
    }


private:

    Node* _LeftMost(Node* root)
    {
        if (root == nullptr)
        {
            return nullptr;
        }
        if (root->_pLeft == nullptr)
        {
            return root;
        }
        
        return _LeftMost(root->_pLeft);

    }

    Node* _RightMost(Node* root)
    {
        if (root == nullptr)
        {
            return nullptr;
        }
        if (root->_pRight == nullptr)
        {
            return root;
        }

        return _RightMost(root->_pRight);
    }


    bool _IsValidRBTRee(Node* pRoot, size_t blackCount, size_t pathBlack)
    {
        if (pRoot == nullptr)
        {
            return blackCount == pathBlack ? true : false;
        }

        if (pRoot->_col == black)
        {
            blackCount++;
        }


        return _IsValidRBTRee(pRoot->_pLeft,blackCount,pathBlack)&&_IsValidRBTRee(pRoot->_pRight,blackCount,pathBlack);

    }

    size_t getBNum(Node* root)
    {
        if (root == nullptr)
        {
            return 0;
        }
        
        if (root->_col == black)
            return 1 + getBNum(root->_pLeft);

        return getBNum(root->_pLeft);

    }




    // 左单旋
    void RotateL(Node* pParent)
    {
        Node* pSonRight = pParent->_pRight;
        Node* pGrand = pParent->_pParent;

        pParent->_pRight = pSonRight->_pLeft;
        if (pSonRight->_pLeft)
        {
            pSonRight->_pLeft->_pParent = pParent;
        }


        pParent->_pParent = pSonRight;
        pSonRight->_pParent = pGrand;
        pSonRight->_pLeft = pParent;


        if (pGrand)
        {
            if (pGrand->_pLeft == pParent)
            {
                pGrand->_pLeft = pSonRight;
            }
            else
            {
                pGrand->_pRight = pSonRight;
            }

        }
        /*pSonRight->_bf = 0;
        pParent->_bf = 0;*/
        //如果旋转节点为根节点还要对根节点进行更新
        if (pParent == _pRoot)
        {
            _pRoot = pSonRight;
        }

    }

    // 右单旋
    void RotateR(Node* pParent)
    {
        Node* pSonLeft = pParent->_pLeft;
        Node* pGrand = pParent->_pParent;

        //将孩子的右节点给父母节点
        pParent->_pLeft = pSonLeft->_pRight;
        //右节点不为空还要改右节点的父母
        if (pSonLeft->_pRight)
        {
            pSonLeft->_pRight->_pParent = pParent;
        }

        pParent->_pParent = pSonLeft;
        pSonLeft->_pParent = pGrand;
        pSonLeft->_pRight = pParent;


        if (pGrand)
        {
            if (pGrand->_pLeft == pParent)
            {
                pGrand->_pLeft = pSonLeft;
            }
            else
            {
                pGrand->_pRight = pSonLeft;
            }

        }
        //pSonLeft->_bf = 0;
        //pParent->_bf = 0;

        //如果旋转节点为根节点还要对根节点进行更新
        if (pParent == _pRoot)
        {
            _pRoot = pSonLeft;
        }


    }



    // 右左双旋
    void RotateRL(Node* pParent)
    {

        RotateR(pParent->_pRight);
        RotateL(pParent);

    }

    // 左右双旋
    void RotateLR(Node* pParent)
    {

        RotateL(pParent->_pLeft);
        RotateR(pParent);


    }





    // 为了操作树简单起见:获取根节点
    Node*& GetRoot()
    {
        return _pRoot;
    }



    


private:
    //将树按中序显示的函数
    void _showTree(Node* root)
    {
        if (root == nullptr)
        {
            return;
        }
        _showTree(root->_pLeft);

        cout << root->_data << " ";

        _showTree(root->_pRight);

    }

    //对树进行删除的函数
    void destoryTree(Node* root)
    {
        if (root == nullptr)
        {
            return;
        }

        destoryTree(root->_pLeft);
        destoryTree(root->_pRight);
        delete root;
        root = nullptr;
    }


    //Node* _pHead;
    Node* _pRoot;

};




int main()
{
    RBTree<int> t;
    t.Insert(2);
    t.Insert(5);
    t.Insert(3);
    t.Insert(4);
    t.Insert(1);
    t.Insert(8);
    
    t.showTree();
    printf("\n");

    //RBTreeNode<int>* tn = t.Find(4);
    //printf("%p",tn);

    printf("最右侧节点值:%d\n",t.RightMost()->_data);
    printf("最左侧节点值:%d\n",t.LeftMost()->_data);

    if (t.IsValidRBTRee())
    {
        printf("恭喜,红黑树创建成功!\n");
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值