文章目录
一、红黑树源码
本文用于封装的红黑树代码(无erase接口):
enum Color
{
BLACK,
RED
};
template<class K, class V>
struct BRTreeNode
{
BRTreeNode<K, V>* _left;
BRTreeNode<K, V>* _right;
BRTreeNode<K, V>* _parent;
pair<K, V> _kv;
Color _col;
BRTreeNode(const pair<K, V>& kv)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_kv(kv)
,_col(RED)
{ }
};
template<class K, class V>
class BRTree
{
typedef BRTreeNode<K, V> Node;
public:
// 在红黑树中插入值为kv的节点
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->_right;
}
else if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(kv);
//新增在左
if (parent->_kv.first > kv.first)
{
parent->_left = cur;
}
else//新增在右
{
parent->_right = cur;
}
cur->_parent = parent;
//更新颜色
//检查是否需要更新颜色,若parent为黑则无需更新
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent;
Node* uncle = nullptr;
if (grandfather->_left == parent)
{
uncle = grandfather->_right;
}
else
{
uncle = grandfather->_left;
}
if (uncle && uncle->_col == RED)//uncle存在且为红——变色
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
if (grandfather->_parent)
{
if (grandfather->_col == BLACK)
{
break;
}
else
{
cur = grandfather;
parent = cur->_parent;
}
}
else
{
grandfather->_col = BLACK;
break;
}
}
else//uncle不存在或uncle存在且为黑——旋转+变色
{
//判断何种情况,该用何种旋转
if (grandfather->_right == parent)
{
if (cur == parent->_right)
{
// g
// p
// c
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
// g
// p
// c
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
}
else
{
if (cur == parent->_left)
{
// g
// p
// c
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
// g
// p
// c
RotateL(parent);
RotateR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
}
break;
}
}
_root->_col = BLACK;
return true;
}
二、控制红黑树的模板参数
我们知道,map是KV模型,键值是pair<Key, Value>;而set是K模型,键值是Key。
那如何使得一颗KV模型的红黑树可以同时适配这两种模型呢?
首先我们控制map和set传入底层红黑树的模板参数,为了与原红黑树的模板参数进行区分,我们将红黑树第二个模板参数的名字改为T,意为通用参数。
template<class K, class T>
class BRTree
对于set,我们传入Key:
template<class K>
class set
{
public:
//...
private:
BRTree<K, K> _t;
};
对于map,我们传入键值对:
template<class K, class V>
class map
{
public:
//...
private:
BRTree<K, pair<K, V>> _t;
};
细心的朋友可以发现,在红黑树中,第一个模板参数K似乎多余了,因为模板参数T中也含有Key。
那么,可以省略第一个模板参数K吗?
看似无伤淡雅,实则不然。
对于set来说,确实没啥影响,因为set传入红黑树的两个模板参数是一样的。
但对于map来说,部分接口的函数参数是要求直接给出Key值的,例如find和erase。
既然我们改了红黑树的参数了,那节点类也得改改了。
对于模板参数,我们只需T即可,并没有任何用到K的地方。
成员我们依次更改一下类型即可:
template<class T>
struct BRTreeNode
{
BRTreeNode<T>* _left;
BRTreeNode<T>* _right;
BRTreeNode<T>* _parent;
T _data;
Color _col;
BRTreeNode(const T& data)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_data(data)
,_col(RED)
{ }
};
三、提取Key,仿函数的添加
在红黑树的find、insert等的接口中,需要对T类型的数据进行比较操作。
对于set来说,没啥问题;
但对于map,其类型为pair<K, V>,我们且来看看pair的比较运算符的重载是否符合我们的要求(只比较Key(first)的值)。

可以看到,pair的比较方式是:先比较first,若不为真,就再比较second
显然,这是不符合map的要求的。
既然如此,我们就需要利用仿函数来手动解决了。
目标仿函数功能:提取出pair<Key,Val>中的Key
设置红黑树仿函数模板参数为KeyOfT:
template<class K, class T, class KeyOfT>
class BRTree
在map中:
template<class K, class V>
class map
{
//作为内部类
//提取key
struct MapKeyOfT
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
public:
//...
private:
BRTree<K, pair<K, V>, MapKeyOfT> _t;
虽然对于set无需这般操作,但红黑树必须添加这个模板参数,set也只能无奈“陪跑”了。
template<class K>
//仿函数提取key
struct SetKeyOfT
{
const K& operator()(const K& Key)
{
return Key;
}
};
class set
{
public:
//...
private:
BRTree<K, K, SetKeyOfT> _t;
};
四、普通迭代器的实现
迭代器的本质就是对指针进行封装,然后重载一些操作符,以至于我们可以像普通指针一样地对数据结构进行操作。
在红黑树中,迭代器必然封装的是节点指针,因此节点指针就是我们迭代器的成员。
template<class T, class T*, class T&>
struct TreeIterator
{
typedef BRTreeNode<T> Node;//节点类型
typedef TreeIterator<T, Ptr, Ref> Self;//迭代器类型
Node* _node;//迭代器所封装的指针
};
接下来我们来一一实现他重要的运算符的重载:
当对迭代器进行解引用操作时,直接返回其对应结点数据的引用即可
T& operator*()
{
return _node->_data; //返回结点数据的引用
}
当对迭代器进行->操作时,直接返回其对应结点数据的指针即可
T* operator->()
{
return &_node->_data; //返回结点数据的指针
}
当对两迭代器进行比较时,我们还需要==和!=运算符
//判断两个正向迭代器是否不同
bool operator!=(const Self& s) const
{
return _node != s._node; //判断两个正向迭代器所封装的结点是否是同一个
}
//判断两个正向迭代器是否相同
bool operator==(const Self& s) const
{
return _node == s._node; //判断两个正向迭代器所封装的结点是否是同一个
}
上面几个都是“开胃小菜”,真正的大餐来了😏
operator++实现
迭代器进行++操作后,应该根据红黑树中序遍历的序列找到当前结点的下一个结点。

【核心逻辑】
- 如果当前节点的右子树不为空时,则下一个访问节点应该在右子树的最左节点(最小节点)
- 如果当前节点的右子树为空时,则下一个访问节点应该在该节点的的祖先节点中,找到上一个孩子是父亲的左孩子的那个祖先。
代码:
// 迭代器的++操作,让迭代器可以移动
Self& operator++()
{
//右子树存在,下一个访问节点是右子树的最左节点
if (_node->_right)
{
Node* LeftMax = _node->_right;
while (LeftMax->_left)
{
LeftMax = LeftMax->_left;
}
_node = LeftMax;
}
else//右子树不存在,沿着祖先路径往上寻找存在左孩子的那个祖先
{
Node* cur = _node;
Node* parent = cur->_parent;;
while (parent)
{
if (cur == parent->_left)
break;
else
{
cur = parent;
parent = parent->_parent;
}
}
_node = parent;
}
return *this;
}
还有operator--,是同理的,左右反一下就好了,笔者这里留下发挥空间。
迭代器的实现到这基本告一段落了,我们现在来给红黑树、map、set配置迭代器:
红黑树:
template<class K, class T, class KeyOfT>
class BRTree
{
typedef BRTreeNode<T> Node;
public:
//注意这里要typedef在public内,否则就是私有成员了,map和set就无法访问了
typedef TreeIterator<T, T*, T&> Iterator;
//返回最左节点
Iterator _begin()
{
Node* LeftMax = _root;
while (LeftMax->_left)
{
LeftMax = LeftMax->_left;
}
return Iterator(LeftMax);
}
Iterator _end()
{
return Iterator(nullptr);
}
//…………
};
map:
template<class K, class V>
class map
{
//提取key
struct MapKeyOfT
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
public:
typedef typename BRTree<K, pair<const K, V>, MapKeyOfT>::Iterator iterator;
iterator begin()
{
return _t._begin();
}
iterator end()
{
return _t._end();
}
private:
BRTree<K, pair<const K, V>, MapKeyOfT> _t;
};
set:
template<class K>
class set
{
//仿函数提取key
struct SetKeyOfT
{
const K& operator()(const K& Key)
{
return Key;
}
};
public:
typedef typename BRTree<K, K, SetKeyOfT>::Iterator iterator;
iterator begin()
{
return _t._begin();
}
iterator end()
{
return _t._end();
}
private:
BRTree<K, K, SetKeyOfT> _t;
};
五、const迭代器的实现
const迭代器的实现并不难,难的是后续会引发一系列复杂的问题,后文基本上都是在解决这些问题。
将红黑树传入迭代器的T*、T&参数用const修饰
typedef TreeIterator<T, const T*, const T&> const_Iterator;
此时,迭代器的模板参数就不能用具体的参数了,将T*换成Ptr,T&换成Ref,以便const T*和const T&的传入。
template<class T, class Ptr, class Ref>
struct TreeIterator
然后在map和set中也需要和普通迭代器一样去定义
最后在红黑树、map、set中实现const_iterator的begin()、end()接口
六、设置Key值不可修改
我们知道,map和set中的Key是不可修改的,如何做到呢?
对于set,我们使用“障眼法”(记住这个障眼法,后文要考):
typedef typename BRTree<K, K, SetKeyOfT>::const_Iterator iterator;
typedef typename BRTree<K, K, SetKeyOfT>::const_Iterator const_iterator;
对于map,我们巧妙地将传入底层红黑树的pair<K, V>改为pair<const K, V>,方可实现Key值无法修改。
七、修改insert的返回值 + operator[]的实现
我们知道,operator[]的本质是插入,它是调用insert的接口实现的,且insert的返回值被设置为pair<iterator, bool>。(上篇有详细介绍)
1. 修改insert返回值
非常简单,我们将原本的返回值和当前插入节点的迭代器make_pair即可。
然后我们修改map和set的接口:
对于map,直接修改insert返回值即可
pair<iterator, bool> insert(const pair<K, V>& kv)
{
return _t._Insert(kv);
}
然而对于set,出大事了!
如果和map一样处理的话,是会报错的,为什么呢?
//错误写法
pair<iterator, bool> insert(const K& key)
{
return _t._Insert(key);
}
还记得我们之前使用的妙计“障眼法”吗?
没错,我们现在要来付出代价了🤣
在set中,iterator是“假“”的,它本质上是const_iterator,而我们insert返回值中的iterator是“货真价实”的iterator。
错误点:用pair<const_iterator, bool>类型作为返回值类型去返回pair<iterator, bool>类型的值。
别看它们长得像,它们可是两个不同的类型!
【解决方案】
用一个pair<iterator, bool>类型的变量ret去接收insert的返回值,然后再用iterator去构造成const_iterator,再返回。
//正确写法
pair<iterator, bool> insert(const K& key)
{
pair<typename BRTree<K, K, SetKeyOfT>::Iterator, bool> Ret = _t._Insert(key);
//用iterator去构造成const_iterator,再返回
return pair<iterator, bool>(Ret.first, Ret.second);
}
还没完,我们的迭代器还不支持用普通迭代器去构造const迭代器,我们需要去写一个构造函数:
typedef TreeIterator<T, T*, T&> iterator;
TreeIterator(const iterator& it)
:_node(it._node)
{}
别看这个函数普普通通,其实别有洞天:
- 当这个迭代器类被实例化为const迭代器,这个函数的作用是一个构造函数。可以用普通迭代器去构造一个const迭代器。
- 当这个迭代器类被实例化为普通迭代器,这个函数就是一个拷贝构造函数。
2. operator[]
直接返回insert返回的迭代器的value即可
V& operator[](const K& key)
{
pair<iterator, bool> Ret = insert(make_pair(key, V()));
return Ret.first->second;
}
八、封装后的源代码
虽然封装过程已经阐述完毕了,但在代码更改过程中还是有许多细节的,下面给出完整封装后的代码。
1. 红黑树
enum Color
{
BLACK,
RED
};
template<class T>
struct BRTreeNode
{
BRTreeNode<T>* _left;
BRTreeNode<T>* _right;
BRTreeNode<T>* _parent;
Color _col;
T _data;
BRTreeNode(const T& data)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_data(data)
,_col(RED)
{ }
};
template<class K, class T, class KeyOfT>
class BRTree
{
typedef BRTreeNode<T> Node;
public:
typedef TreeIterator<T, T*, T&> Iterator;
typedef TreeIterator<T, const T*, const T&> const_Iterator;
Iterator _begin()
{
Node* LeftMax = _root;
while (LeftMax->_left)
{
LeftMax = LeftMax->_left;
}
return Iterator(LeftMax);
}
Iterator _end()
{
return Iterator(nullptr);
}
const_Iterator _begin() const
{
Node* LeftMax = _root;
while (LeftMax->_left)
{
LeftMax = LeftMax->_left;
}
return const_Iterator(LeftMax);
}
const_Iterator _end() const
{
return const_Iterator(nullptr);
}
//查找
Node* _find(const K& key)
{
if (_root == nullptr)
{
return nullptr;
}
Node* cur = _root;
while (cur)
{
if (kot(cur->_data) < key)
{
cur = cur->_right;
}
else if (kot(cur->_data) > key)
{
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}
// 在红黑树中插入值为val的节点
pair<Iterator, bool> _Insert(const T& data)
{
if (_root == nullptr)
{
_root = new Node(data);
_root->_col = BLACK;
return make_pair(_root, true);
}
KeyOfT kot;
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (kot(cur->_data) < kot(data))
{
parent = cur;
cur = cur->_right;
}
else if (kot(cur->_data) > kot(data))
{
parent = cur;
cur = cur->_left;
}
else
{
return make_pair(cur, false);
}
}
cur = new Node(data);
Node* newnode = cur;
//新增在左
if (kot(parent->_data) > kot(data))
{
parent->_left = cur;
}
else//新增在右
{
parent->_right = cur;
}
cur->_parent = parent;
//更新颜色
//检查是否需要更新颜色,若parent为黑则无需更新
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent;
Node* uncle = nullptr;
if (grandfather->_left == parent)
{
uncle = grandfather->_right;
}
else
{
uncle = grandfather->_left;
}
if (uncle && uncle->_col == RED)//uncle存在且为红——变色
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
if (grandfather->_parent)
{
if (grandfather->_col == BLACK)
{
break;
}
else
{
cur = grandfather;
parent = cur->_parent;
}
}
else
{
grandfather->_col = BLACK;
break;
}
}
else//uncle不存在或uncle存在且为黑——旋转+变色
{
//判断何种情况,该用何种旋转
if (grandfather->_right == parent)
{
if (cur == parent->_right)
{
// g
// p
// c
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
// g
// p
// c
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
}
else
{
if (cur == parent->_left)
{
// g
// p
// c
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
else
{
// g
// p
// c
RotateL(parent);
RotateR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
}
break;
}
}
_root->_col = BLACK;
return make_pair(newnode, true);
}
2. 迭代器
template<class T, class Ptr, class Ref>
struct TreeIterator
{
typedef BRTreeNode<T> Node;
typedef TreeIterator<T, Ptr, Ref> Self;
typedef TreeIterator<T, T*, T&> iterator;
Node* _node;
TreeIterator(const iterator& it)
:_node(it._node)
{ }
TreeIterator(Node* node)
:_node(node)
{ }
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
// 迭代器的++操作,让迭代器可以移动
Self& operator++()
{
//右子树存在,下一个访问节点是右子树的最左节点
if (_node->_right)
{
Node* LeftMax = _node->_right;
while (LeftMax->_left)
{
LeftMax = LeftMax->_left;
}
_node = LeftMax;
}
else//右子树不存在,沿着祖先路径往上寻找存在左孩子的那个祖先
{
Node* cur = _node;
Node* parent = cur->_parent;;
while (parent)
{
if (cur == parent->_left)
break;
else
{
cur = parent;
parent = parent->_parent;
}
}
_node = parent;
}
return *this;
}
Self operator++(int)
{
Self tmp(*this);
//右子树存在,下一个访问节点是右子树的最左节点
if (_node->_right)
{
Node* LeftMax = _node->_right;
while (LeftMax->_left)
{
LeftMax = LeftMax->_left;
}
_node = LeftMax;
}
else//右子树不存在,沿着祖先路径往上寻找存在左孩子的那个祖先
{
Node* cur = _node;
Node* parent = cur->_parent;;
while (parent)
{
if (cur == parent->_left)
break;
else
{
cur = parent;
parent = parent->_parent;
}
}
_node = parent;
}
return tmp;
}
Self& operator--()
{
//左子树存在,下一个访问节点是左子树的最右节点
if (_node->_left)
{
Node* RightMax = _node->_left;
while (RightMax->_right)
{
RightMax = RightMax->_right;
}
_node = RightMax;
}
else//左子树不存在,沿着祖先路径往上寻找存在右孩子的那个祖先
{
Node* cur = _node;
Node* parent = cur->_parent;;
while (parent)
{
if (cur == parent->_right)
break;
else
{
cur = parent;
parent = parent->_parent;
}
}
_node = parent;
}
return *this;
}
Self operator--(int)
{
Self tmp(*this);
//左子树存在,下一个访问节点是左子树的最右节点
if (_node->_left)
{
Node* RightMax = _node->_left;
while (RightMax->_right)
{
RightMax = RightMax->_right;
}
_node = RightMax;
}
else//左子树不存在,沿着祖先路径往上寻找存在右孩子的那个祖先
{
Node* cur = _node;
Node* parent = cur->_parent;;
while (parent)
{
if (cur == parent->_right)
break;
else
{
cur = parent;
parent = parent->_parent;
}
}
_node = parent;
}
return tmp;
}
// 让迭代器能够支持比较
bool operator!=(const Self& s)const
{
return _node != s._node;
}
bool operator==(const Self& s)const
{
return _node == s._node;
}
};
3. set
#pragma once
#include"BRTree.h"
namespace Surplus
{
template<class K>
class set
{
//仿函数提取key
struct SetKeyOfT
{
const K& operator()(const K& Key)
{
return Key;
}
};
public:
typedef typename BRTree<K, K, SetKeyOfT>::const_Iterator iterator;
typedef typename BRTree<K, K, SetKeyOfT>::const_Iterator const_iterator;
const_iterator begin() const
{
return _t._begin();
}
const_iterator end() const
{
return _t._end();
}
pair<iterator, bool> insert(const K& key)
{
pair<typename BRTree<K, K, SetKeyOfT>::Iterator, bool> Ret = _t._Insert(key);
return pair<iterator, bool>(Ret.first, Ret.second);
}
private:
BRTree<K, K, SetKeyOfT> _t;
};
}
4. map
#pragma once
#include"BRTree.h"
namespace Surplus
{
template<class K, class V>
class map
{
//提取key
struct MapKeyOfT
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
public:
typedef typename BRTree<K, pair<const K, V>, MapKeyOfT>::Iterator iterator;
typedef typename BRTree<K, pair<const K, V>, MapKeyOfT>::const_Iterator const_iterator;
iterator begin()
{
return _t._begin();
}
iterator end()
{
return _t._end();
}
const_iterator begin() const
{
return _t._begin();
}
const_iterator end() const
{
return _t._end();
}
V& operator[](const K& key)
{
pair<iterator, bool> Ret = insert(make_pair(key, V()));
return Ret.first->second;
}
pair<iterator, bool> insert(const pair<K, V>& kv)
{
return _t._Insert(kv);
}
private:
BRTree<K, pair<const K, V>, MapKeyOfT> _t;
};
}
1057

被折叠的 条评论
为什么被折叠?



