STL-红黑树源码实现

红黑树的介绍

它是一种特殊的二叉查找树,红黑树的每个节点上都有存储位表示节点的颜色,可以是红或者黑。

红黑树的特性

1.每个节点或者黑色或者红色

2.根节点是黑色

3.每个叶子节点是黑色

4.如果一个节点是红色,它的子节点必须是黑色的

5.从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点

红黑树的操作

左旋

对x进行左旋,意味着“将X变为一个左节点”

右旋

平衡调节

新插入X,父节点P,G是P的父节点,S是G的另外一个子节点。

新节点x必须为叶节点,插入的节点必须为红色;

如果P是红色,必须调整红色,根据X的插入位置,有4种情况:

1:S为黑色且X为外侧插入,先对P,G左一次单旋转,在更改P,G颜色,重新满足红黑树的规则3:

2.S为黑且X为内侧插入,先对P,X做一次单旋转并更改G,X颜色,再将结果对G做一次单旋转,满足红黑树的规则

3.S为红色,且X为外侧插入,先对P和G做一次单旋转,并改变X的颜色,此时,如果GG(G的父节点)为黑色,符合规则;否则,进入情况4

 

或者

4.S为红色且X为外侧插入,先对P和G做一次单旋转,并改变X的颜色,如果G的父节点,仍然为红色,继续往上做,直到父子连续部位红的情况。

或者

 

红黑树的实现

节点的定义

struct _Node {
        _Nodeptr _Left, _Parent, _Right;
        _Ty _Value;
        _Redbl _color;
    };

节点的父节点,左右孩子节点

 

初始化

申请一个节点,赋值给_Nil, 并且左右子节点为0;并在构造一个节点_Head,并且设置为红色节点,父指针指向_Nil节点,左右子节点都指向自己。

_Head节点和红黑树的根节点的父节点,是相互指向。

_Nil用来表示null节点。

_Lmost,指向最左边的节点,_Rmost,指向最右边的节点,可以用来求最小和最大值。

void _Init() {
        _Nodeptr _Tmp = _Buynode(0, _Black);
        {
            _Lockit _Lk;
            if (_Nil == 0) {
                _Nil = _Tmp;
                _Tmp = 0;
                _Left(_Nil) = 0, _Right(_Nil) = 0;
            }
            ++_Nilerefs;
        }
        if (_Tmp != 0) {
            _Freenode(_Tmp);
        }
        _Head = _Buy(_Nil, _Red), _Size = 0;
        _Lmost() = _Head, _Rmost() = _Head;
    }

数据的插入

实现左旋

_Nodeptr _Y = _Right(_X);
        _Right(_X) = _Left(_Y);
        if (_Left(_Y) != _Nil) {
            _Parent(_Left(_Y)) = _X;
        }
        _Parent(_Y) = _Parent(_X);
        if (_X == _Root()) {
            _Root() = _Y;
        }
        else if (_X == _Left(_Parent(_X))) {
            _Left(_Parent(_X)) = _Y;
        }
        else {
            _Right(_Parent(_X)) = _Y;
        }
        _Left(_Y) = _X;
        _Parent(_X) = _Y;
    }

实现右旋

void _Rrotate(_Nodeptr _X) {
        _Nodeptr _Y = _Left(_X);
        _Left(_X) = _Right(_Y);
        if (_Right(_Y) != _Nil) {
            _Parent(_Right(_Y)) = _X;
        }
        _Parent(_Y) = _Parent(_X);
        if (_X == _Root())
            _Root() = _Y;
        else if (_X == _Right(_Parent(_X))) {
            _Right(_Parent(_X)) = _Y;
        }
        else {
            _Left(_Parent(_X)) = _Y;
        }
        _Right(_Y) = _X;
        _Parent(_X) = _Y;
    }

红黑树删除

红黑树的删除分为两种情况,情况1是有两个子的情况,情况2最多有一个子树的情况

 _Nodeptr _X;
        _Nodeptr _Y = (_P++)._Mynode();
        _Nodeptr _Z = _Y;

_Y:表示的是要删除的节点,_P表示的是临近_Y的大的节点

_Z:赋值为_Y

情况1:最多有一个子树的情况

  •    如果左子树或者右子树为空的情况   

if (_Left(_Y) == _Nil) {
            _X = _Right(_Y);
        }
        else if (_Right(_Y) == _Nil) {
            _X = _Left(_Y);
        }

 

把_X分别设置为右子树和左子树。

  • 然后把_X的父节点,设置为_Y的父节点即可;

      _Parent(_X) = _Parent(_Y);

  • 特殊情况判断,如果为root()节点

if (_Root() == _Z)
                _Root() = _X;

否则就设置_Z的左右子树

else if (_Left(_Parent(_Z)) == _Z) {
                _Left(_Parent(_Z)) = _X;
            }
            else {
                _Right(_Parent(_Z)) = _X;
            }

  • 判断是否为_Lmost  

if (_Lmost() != _Z) {
                ;
            }

如果_Z是_Lmost就把_Z的父节点,设置为_Lmost
            else if (_Right(_Z) == _Nil) {
                _Lmost() = _Parent(_Z);
            }
            else {
                _Lmost() = _Min(_X);
            }

_Rmost的判断是同样的。

情况2:有两个子树的情况


            _Y = _Min(_Right(_Y));
            _X = _Right(_Y);

去_Y的右子树的最小节点,然后把_X置为该节点的右数,_Z是要删除的节点。目的是把_Y这个节点,放到_Z的位置上去;接下来就是要调整,_Z,_Y的左右子树和父节点的指向。

  • 更新_Z的左右子树的父节点的指向为_Y

_Parent(_Left(_Z)) = _Y;

  • 更新_Y的左子树的指向为_Z的左子树的指向

 _Left(_Y) = _Left(_Z);

  • 如果恰好_Y==_Right(_Z)

if (_Y == _Right(_Z)) {
                _Parent(_X) = _Y;
            }

  • 否则

                    _Parent(_X) = _Parent(_Y);
                    _Left(_Parent(_Y)) = _X;
                    _Right(_Y) = _Right(_Z);
                    _Parent(_Right(_Z)) = _Y;

删除后平衡调整

如果删除的是黑色节点,才需要进行平衡调整。

分析左子树的情况:

while (_X != _Root() && _Color(_X) == _Black) {
                if (_X == _Left(_Parent(_X))) {

  • 获取_X节点的父节点的右子树

_Nodeptr _W = _Right(_Parent(_X));

  • 如果_W的颜色是红色

_Color(_W) = _Black;
                        _Color(_Parent(_X)) = _Red;
                        _Lrotate(_Parent(_X));
                        _W = _Right(_Parent(_X));

if (_Color(_Left(_W)) == _Black&&_Color(_Right(_W)==_Black) {
                        _Color(_W)=_Red;
                        _X=_Parent(_X);
                    }
                    else {
                        if (_Color(_Right(_W)) == _Black) {
                            _Color(_Left(_W))=_Black;
                            _Color(_W)=_Red;
                            _Rrotate(_W);
                            _W=_Right(_Parent(_X));
                        }
                        _Color(_W) = _Color(_Parent(_X));
                        _Color(_Parent(_X)) = _Black;
                        _Color(_Right(_W)) = _Black;
                        _Lrotate(_Parent(_X));
                        break;

                    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C++ STL中,红黑树实现被封装在`std::map`和`std::set`这两个容器类中。这两个容器类都是基于红黑树实现的,它们提供了高效的查找、插入和删除操作,保证了元素的有序性。 STL中的红黑树实现与你提供的C++代码略有不同。STL中的红黑树使用节点颜色(红色或黑色)和节点指针(parent、left、right)来表示树的结构,而你提供的代码使用了模板和节点对象来实现。 在STL中,红黑树的插入和删除操作已经被封装在`std::map`和`std::set`中,使用起来非常简单。你只需要包含相应的头文件`<map>`或`<set>`,并使用`std::map`或`std::set`类来定义变量,就可以直接使用红黑树的功能了。 以下是使用STL红黑树的简单示例: ```cpp #include <map> int main() { std::map<int, std::string> myMap; // 插入元素 myMap.insert(std::make_pair(1, "one")); myMap = "two"; // 查找元素 auto it = myMap.find(1); if (it != myMap.end()) { std::cout << it->second << std::endl; // 输出 "one" } // 删除元素 myMap.erase(2); return 0; } ``` 在上面的示例中,我们使用`std::map`来创建一个键-值对的红黑树。我们使用`insert`函数插入元素,使用`find`函数查找元素,使用`erase`函数删除元素。 总结一下,C++ STL中的红黑树实现被封装在`std::map`和`std::set`中,使用起来非常方便。你可以直接包含相应的头文件,并使用这些类来实现红黑树的功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值