红黑树详解

红黑树

红黑树是一棵二叉搜索树,它在每一个节点上增加了一个表示颜色的指针,红色或者黑色。
一棵红黑树是满足下面性质的二叉搜索树:

  1. 每个节点非红即黑
  2. 根结点是黑色的
  3. 每个叶节点(这里的叶节点是指NULL节点)是黑色的
  4. 如果一个节点是红的,那么两个子节点都是黑的
  5. 对于任一节点,从该节点到所有后代叶节点的路径上,黑色节点的数目相等

由于这些性质的约定,红黑树没有一条路径会比其他路径长出两倍,因而红黑树是近似平衡的。


红黑树在插入和删除时会对树进行修改,可能会违反上面列出的红黑树的性质,因此需要对树作出相应的调整。

插入

说明:为了满足性质5,我们默认新增节点的颜色为红色
并且约定:cur为当前插入节点、p为插入节点父节点、g为祖父节点,u为叔叔节点。

情况一
若树为空,为了满足性质2,需将新增节点改成黑色

情况二
插入节点的父节点为黑色,直接插入

情况三
插入节点的父节点为红色

这里根据叔叔节点的不同又分两种情况讨论:

1)叔叔节点存在且为红
调整方法:将p和u改成黑,g改成红,然后把p当成cur继续向上迭代调整。
这里写图片描述
2)叔叔节点不存在或着为黑
根据p和cur的位置的不同分为四种情况:

①p为g的左孩子,cur为p的左孩子
调整方法:进行右单旋,并且p变为黑色,g变为红色,此时经过调整后的根结点已经为黑色,故不需要向上调整
这里写图片描述

②p为g的右孩子,cur为p的右孩子
调整方法:进行左单旋,并且p变为黑色,g变为红色,此时经过调整后的根结点已经为黑色,故不需要向上调整
这里写图片描述

③p为g的左孩子,cur为p的右孩子
调整方法:针对p进行左单旋,从而转化为情况①
这里写图片描述

④p为g的右孩子,cur为p的左孩子
调整方法:针对p进行右单旋,从而转化为情况②
这里写图片描述

删除

红黑树的删除和二叉搜索树的删除操作类似,但是红黑树在删除节点后需要进行相应的调整,使其仍然满足红黑树的性质。当被删除节点左右节点都不为空的情况下,我们需要在其右子树寻找最左节点或者在其左子树寻找最右边的节点作为真正要被删除的替换节点(金蝉脱壳),被删节点与替换节点交换后,把替换节点删除即可。
注意,此时待删除的节点要么没有孩子节点,要么只有左子树或者只有右子树

下面主要说明在删除替换节点后,怎样重新调整红黑树

情况一
删除的节点为红色节点,直接删除

情况二
删除的节点为黑色,显然删除一个黑色节点后会违反性质5,需要进行调整,

1)有孩子节点并且孩子节点为红色
直接删除节点并把孩子节点变为黑色
注意要删除节点为根结点的情况:
这里写图片描述
2)无孩子节或者孩子节点为黑色(事实上孩子节点为黑的情况一定不存在)

分为以下五种情况:
注:约定N为待删节点,P为父节点,S为兄弟节点
①S为红色(p和S的子节点一定为黑),N是P的左孩子(或者右孩子)
操作:以S为轴心左旋,并且把S变为黑,P变为红
这里写图片描述
此时删除N节点后,在N节点的路径上少了一个黑节点,因此需要以N为开始重新向上调整

②P和S都为黑,且S的孩子们也都为黑
操作:S变为红色
这里写图片描述
此时删除S变色后,并且删除N后,以P为根结点的子树的黑节点减少了两个,因此需要以P为开始重新向上调整

③P为红(S一定为黑),S的孩子们为黑
操作:P改为黑,S改为红
这里写图片描述
此时,在删除N节点后黑节点的数目无变化,无需调整

④P为任意颜色,S为黑,N是P的左孩子,S的右孩子SR为红(或者是N是P的右孩子,S的左孩子为红,S的右孩子任意)
操作:以S为中心左旋,SR(SL)改为黑,P改为黑,S改为P的颜色
这里写图片描述
此时,删除N后,黑节点数目无变化,无需调整

⑤P任意色,S为黑,N是P的左孩子,S的左孩子SL为红,S的右孩子SR为黑(或者N是P的有孩子,S的右孩子为红,S的左孩子为黑)
操作:以SL为中心进行左旋,并且S变为红,SL变为黑
这里写图片描述
此时,变成了情况④
至此,删除的所有情况已经分析完毕。

C++代码:

#pragma once
#include<utility>
#include<algorithm>
#include<iostream>

using namespace std;

enum Color
{
    RED = 0,
    BLACK
};

template<typename K, typename V>
struct RBTreeNode
{
    RBTreeNode* _pLeft;
    RBTreeNode* _pRight;
    RBTreeNode* _pParent;
    Color _color;
    pair<K, V> _v;
    RBTreeNode(const K& key, const V& value)
        :_pLeft(NULL)
        , _pRight(NULL)
        , _pParent(NULL)
        , _color(RED)
        , _v(pair<K, V>(key, value))
    {}
};

template<typename K, typename V>
class RBTree
{
    typedef RBTreeNode<K, V> Node;
    typedef Node* pNode;
public:
    RBTree()
        :_pRoot(NULL)
    {}

    bool insert(const K& key, const V& value)
    {
        if (NULL == _pRoot)
        {
            _pRoot = new Node(key, value);
            _pRoot->_color = BLACK;
            return true;
        }

        pNode pCur = _pRoot;
        pNode pParent = NULL;
        while (pCur)
        {
            pParent = pCur;
            if (pCur->_v.first > key)
                pCur = pCur->_pLeft;
            else if (pCur->_v.first < key)
                pCur = pCur->_pRight;
           
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值