图解红黑树

gitee仓库:https://gitee.com/WangZihao64/data-structure-and-algorithm/tree/master/RBTree

概念

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的

红黑树的性质

  1. 每个结点不是红色就是黑色
  2. 根节点是黑色的
  3. 如果一个节点是红色的,则它的两个孩子结点是黑色的
  4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
  5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)

红黑树的调整规则

插入的顺序和avl树一样,根结点为黑色,插入新结点为红色,因为从该结点到后代结点都有相同数量的黑色结点,如果插入黑色,有很大的可能性会失败,所以插入红色结点是最为保险的做法,然后在依据规则进行调整,一般有3种情况

  • 情况一:cur为红,parent为红,grandfather为红,uncle存在且为红色
  • 解决方法:parent,uncle变黑,然后把grandfather给cur,继续向上调整

在这里插入图片描述

  • 情况二:cur为红,parent为红,grandfather为黑,uncle不存在||uncle存在且为黑色

  • 解决方法:parent为grandfather的左孩子,cur为parent的左孩子,对grandfather右旋

                        parent为grandfather的右孩子,cur为parent的右孩子,对grandfather左旋
    
                        **parent变黑,grandfather变红**
    

在这里插入图片描述

  • 情况三:cur为红,parent为红,grandfather为黑,uncle不存在||uncle存在且为黑色
  • 解决方法:parent为grandfather的左孩子,cur为parent的右孩子,对parent左旋,对grandfather右旋

parent为grandfather的右孩子,cur为parent的左孩子,对parent右旋,对grandfather左旋

cur变黑,grandfather变红

在这里插入图片描述

bool Insert(const pair<K,V>& kv)
    {
        if(_root== nullptr)
        {
            //根节点为黑色
            _root=new Node(kv);
            _root->_col=BLACK;
            return true;
        }
        Node* cur=_root;
        Node* parent=nullptr;
        while(cur)
        {
            if(cur->_kv.first>kv.first)
            {
                parent=cur;
                cur=cur->_left;
            }
            else if(cur->_kv.first<kv.first)
            {
                parent=cur;
                cur=cur->_right;
            }
                //遇到相同的值,返回false
            else
            {
                return false;
            }
        }
        cur=new Node(kv);
        if(kv.first>parent->_kv.first)
        {
            parent->_right=cur;
            cur->_parent=parent;
        }
        else
        {
            parent->_left=cur;
            cur->_parent=parent;
        }
        //parent不为空&&parent为红色需要进行调整
        while(parent&&parent->_col==RED)
        {
            Node* grandfather=parent->_parent;
            if(grandfather->_left==parent)
            {
                //情况一:cur为红,parent为红,uncle存在&&为红
                //把p,u变为black,g变为red
                Node* uncle=grandfather->_right;
                if(uncle&&uncle->_col==RED)
                {
                    parent->_col=BLACK;
                    uncle->_col=BLACK;
                    grandfather->_col=RED;
                    //把g变为cur继续向上调整
                    cur=grandfather;
                    parent=cur->_parent;
                }
                    //uncle不存在||uncle存在&&为黑色
                    //这两个可以直接break,因为无论是不是子树,root都是黑色
                else
                {
                    //情况二:parent->left=cur
                    //对grandfater右旋
                    //p变black,g变red
                    if(parent->_left==cur)
                    {
                        RotateR(grandfather);
                        parent->_col=BLACK;
                        grandfather->_col=RED;
                    }
                        //情况三:parent->right=cur
                        //先对cur左旋,在对grandfather右旋
                        //这是会变为情况二,cur变black,g变red
                    else
                    {
                        RotateL(parent);
                        RotateR(grandfather);
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    break;
                }
            }
                //grandfather->right=cur
                //和grandfather->left=cur类似
            else
            {
                //情况一:cur为红,parent为红,uncle存在&&为红
                //把p,u变为black,g变为red
                Node* uncle=grandfather->_left;
                if(uncle&&uncle->_col==RED)
                {
                    parent->_col=BLACK;
                    uncle->_col=BLACK;
                    grandfather->_col=RED;
                    //把g变为cur继续向上调整
                    cur=grandfather;
                    parent=cur->_parent;
                }
                    //uncle不存在||uncle存在&&为黑色
                    //这两个可以直接break,因为无论是不是子树,root都是黑色
                else
                {
                    //情况二:parent->right=cur
                    //对grandfater左旋
                    //p变black,g变red
                    //   g
                    //      p
                    //         c
                    if(parent->_right==cur)
                    {
                        RotateL(grandfather);
                        parent->_col=BLACK;
                        grandfather->_col=RED;
                    }
                        //情况三:parent->left=cur
                        //先对cur右旋,在对grandfather左旋
                        //这是会变为情况二,cur变black,g变red
                        //     g
                        //       p
                        //     c
                    else
                    {
                        RotateR(parent);
                        RotateL(grandfather);
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    break;
                }
            }
        }
        //根节点永远是黑色
        _root->_col=BLACK;
        return true;
    }
    void RotateL(Node* parent)
    {
        Node* subR=parent->_right;
        //右子树的左子树
        Node* subRL=subR->_left;
        //旋转的这棵树有可能是子树,所以需要保存parent的parent
        Node* pparent=parent->_parent;
        parent->_right=subRL;
        subR->_left=parent;
        //subLR可能不存在,需要单独判断
        if(subRL!= nullptr)
        {
            subRL->_parent = parent;
        }
        parent->_parent=subR;
        subR->_parent=pparent;
        //如果parent不是子树,就需要把_root给subR
        if(pparent== nullptr)
        {
            _root=subR;
        }
            //如果parent是子树的话,需要改变pparent的指向
        else if(pparent!= nullptr)
        {
            //子树是pparent的左子树/右子树,需要把pparent-left/->right指向subR
            if(pparent->_left==parent)
            {
                pparent->_left=subR;
            }
            else if(pparent->_right==parent)
            {
                pparent->_right=subR;
            }
        }
    }

    //右旋和左旋是一样的
    void RotateR(Node* parent)
    {
        Node* subL=parent->_left;
        Node* subLR=subL->_right;
        Node* pparent=parent->_parent;
        parent->_left=subLR;
        subL->_right=parent;
        if(subLR!= nullptr)
        {
            subLR->_parent=parent;
        }
        parent->_parent=subL;
        subL->_parent=pparent;
        if(pparent== nullptr)
        {
            _root=subL;
        }
        else if(pparent!= nullptr)
        {
            if(pparent->_left==parent)
            {
                pparent->_left=subL;
            }
            else if(pparent->_right==parent)
            {
                pparent->_right=subL;
            }
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值