> 文章列表 > C++ 红黑树

C++ 红黑树

C++ 红黑树

1.红黑树的概念

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

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

红黑树:

空树

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

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

C++ 红黑树

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. 红黑树结构

C++ 红黑树

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

4.1 红黑树的插入操作

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

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

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

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

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

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

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

C++ 红黑树

情况二: cur为红,p为红,g为黑,u不存在/u存在且为黑

C++ 红黑树

p为g的左孩子,cur为p的左孩子,则进行右单旋转;

相反,p为g的右孩子,cur为p的右孩子,则进行左单旋转

p、g变色--p变黑,g变红

情况三: cur为红,p为红,g为黑,u不存在/u存在且为黑

C++ 红黑树

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()放在头结点的位置

C++ 红黑树

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(){}/// Iteratoriterator begin(){ return _t.Begin();}iterator end(){ return _t.End();}/// Capacitysize_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;// modifypair<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内部封装一棵红黑树,即可将该容器实现出来