C++ 红黑树

1.红黑树的概念

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

径会比其他路径长出俩倍,因而是接近平衡的。

红黑树:

空树

非空:二叉搜索树 + 平衡条件限制(红黑树性质约束)

保证:最长路径中节点个数不超过最短路径中节点个数的2倍

2. 红黑树的性质

1. 每个结点不是红色就是黑色

2. 根节点是黑色的

3. 如果一个节点是红色的,则它的两个孩子结点是黑色的 (不可能有连在一起的红色节点)

4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点 (每条路径中黑色节点个数相同)

5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)

3.红黑树节点的定义

enum Color {RED, BLACK};
// 红黑树节点的定义
template<class ValueType>
struct RBTreeNode
{
 RBTreeNode(const ValueType& data = ValueType(),Color color = RED)
     : _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr)
     , _data(data), _color(color)
 {}
     RBTreeNode<ValueType>* _pLeft;   // 节点的左孩子
     RBTreeNode<ValueType>* _pRight;  // 节点的右孩子
     RBTreeNode<ValueType>* _pParent; // 节点的双亲(红黑树需要旋转,为了实现简单给
                                                                    出该字段)
     ValueType _data;            // 节点的值域
     Color _color;               // 节点的颜色
};

4. 红黑树结构

为了后续实现关联式容器简单,红黑树的实现中增加一个头结点,因为跟节点必须为黑色,为了与根节点进行区分,将头结点给成黑色,并且让头结点的 pParent 域指向红黑树的根节点,pLeft域指向红黑树中最小的节点,_pRight域指向红黑树中最大的节点

4.1 红黑树的插入操作

1. 按照二叉搜索的树规则插入新节点

2. 检测新节点插入后,红黑树的性质是否造到破坏

因为新节点的默认颜色是红色,因此:如果其双亲节点的颜色是黑色,没有违反红黑树任何

性质,则不需要调整;但当新插入节点的双亲节点颜色为红色时,就违反了性质三不能有连

在一起的红色节点,此时需要对红黑树分情况来讨论:

约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点

情况一: cur为红,p为红,g为黑,u存在且为红

情况二: 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

4.2.红黑树的验证

红黑树的检测分为两步:

1. 检测其是否满足二叉搜索树(中序遍历是否为有序序列)

2. 检测其是否满足红黑树的性质

5.红黑树模拟实现STL中的map与set

5.1红黑树的迭代器

begin()与end()

STL明确规定,begin()与end()代表的是一段前闭后开的区间,而对红黑树进行中序遍历后,

可以得到一个有序的序列,因此:begin()可以放在红黑树中最小节点(即最左侧节点)的位

将end()放在头结点的位置

5.2 map的模拟实现

map的底层结构就是红黑树,因此在map中直接封装一棵红黑树,然后将其接口包装下即可

namespace bite
{
 template<class K, class V>
 class map
 {
 typedef pair<K, V> ValueType;
      // 作用:将value中的key提取出来
 struct KeyOfValue
 {
 const K& operator()(const ValueType& v)
 { return v.first;}
 };
     typedef RBTree<K, ValueType, KeyOfValue> RBTree;
     public:
     typedef typename RBTree::Iterator iterator;
     public:
     map(){}
     /
     // Iterator
     iterator begin(){ return _t.Begin();}
     iterator end(){ return _t.End();}
     /
     // Capacity
     size_t size()const{ return _t.Size();}
     bool empty()const{ return _t.Empty();}
        V& operator[](const K& key)
     { return (*(_t.Insert(ValueType(key, V()))).first).second;}
     const V& operator[](const K& key)const;
     
     // modify
     pair<iterator, bool> insert(const ValueType& data) { return
    _t.Insert(data);}
     void clear(){ _t.Clear();}
     iterator find(const K& key){ return _t.Find(key);}
     private:
     RBTree _t;
 };
}

5.3 set的模拟实现

set的底层为红黑树,因此只需在set内部封装一棵红黑树,即可将该容器实现出来

猜你喜欢

转载自blog.csdn.net/weixin_59215611/article/details/129796978