目录
一、适配器红黑树
STL在封装set、map时,直接适配了RBTree——红黑树,这里的红黑树相较上文我们的红黑树,这里实现了构造、拷贝构造、赋值运算符重载、析构、删除节点等函数
//枚举定义结点的颜色
enum Colour
{
RED,
BLACK
};
//红黑树结点的定义
template<class K, class V>
struct RBTreeNode
{
//三叉链
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
//存储的键值对
pair<K, V> _kv;
//结点的颜色
int _col; //红/黑
//构造函数
RBTreeNode(const pair<K, V>& kv)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _kv(kv)
, _col(RED)
{}
};
//红黑树的实现
template<class K, class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
//构造函数
RBTree()
:_root(nullptr)
{}
//拷贝构造
RBTree(const RBTree<K, V>& t)
{
_root = _Copy(t._root, nullptr);
}
//赋值运算符重载(现代写法)
RBTree<K, V>& operator=(RBTree<K, V> t)
{
swap(_root, t._root);
return *this;
}
//析构函数
~RBTree()
{
_Destroy(_root);
_root = nullptr;
}
//查找函数
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (key < cur->_kv.first) //key值小于该结点的值
{
cur = cur->_left; //在该结点的左子树当中查找
}
else if (key > cur->_kv.first) //key值大于该结点的值
{
cur = cur->_right; //在该结点的右子树当中查找
}
else //找到了目标结点
{
return cur; //返回该结点
}
}
return nullptr; //查找失败
}
//插入函数
pair<Node*, bool> Insert(const pair<K, V>& kv)
{
if (_root == nullptr) //若红黑树为空树,则插入结点直接作为根结点
{
_root = new Node(kv);
_root->_col = BLACK; //根结点必须是黑色
return make_pair(_root, true); //插入成功
}
//1、按二叉搜索树的插入方法,找到待插入位置
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (kv.first < cur->_kv.first) //待插入结点的key值小于当前结点的key值
{
//往该结点的左子树走
parent = cur;
cur = cur->_left;
}
else if (kv.first > cur->_kv.first) //待插入结点的key值大于当前结点的key值
{
//往该结点的右子树走
parent = cur;
cur = cur->_right;
}
else //待插入结点的key值等于当前结点的key值
{
return make_pair(cur, false); //插入失败
}
}
//2、将待插入结点插入到树中
cur = new Node(kv); //根据所给值构造一个结点
Node* newnode = cur; //记录新插入的结点(便于后序返回)
if (kv.first < parent->_kv.first) //新结点的key值小于parent的key值
{
//插入到parent的左边
parent->_left = cur;
cur->_parent = parent;
}
else //新结点的key值大于parent的key值
{
//插入到parent的右边
parent->_right = cur;
cur->_parent = parent;
}
//3、若插入结点的父结点是红色的,则需要对红黑树进行调整
while (parent&&parent->_col == RED)
{
Node* grandfather = parent->_parent; //parent是红色,则其父结点一定存在
if (parent == grandfather->_left) //parent是grandfather的左孩子
{
Node* uncle = grandfather->_right; //uncle是grandfather的右孩子
if (uncle&&uncle->_col == RED) //情况1:uncle存在且为红
{
//颜色调整
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
//继续往上处理
cur = grandfather;
parent = cur->_parent;
}
else //情况2+情况3:uncle不存在 + uncle存在且为黑
{
if (cur == parent->_left)
{
RotateR(grandfather); //右单旋
//颜色调整
grandfather->_col = RED;
parent->_col = BLACK;
}
else //cur == parent->_right
{
RotateLR(grandfather); //左右双旋
//颜色调整
grandfather->_col = RED;
cur->_col = BLACK;
}
break; //子树旋转后,该子树的根变成了黑色,无需继续往上进行处理
}
}
else //parent是grandfather的右孩子
{
Node* uncle = grandfather->_left; //uncle是grandfather的左孩子
if (uncle&&uncle->_col == RED) //情况1:uncle存在且为红
{
//颜色调整
uncle->_col = parent->_col = BLACK;
grandfather->_col = RED;
//继续往上处理
cur = grandfather;
parent = cur->_parent;
}
else //情况2+情况3:uncle不存在 + uncle存在且为黑
{
if (cur == parent->_left)
{
RotateRL(grandfather); //右左双旋
//颜色调整
cur->_col = BLACK;
grandfather->_col = RED;
}
else //cur == parent->_right
{
RotateL(grandfather); //左单旋
//颜色调整
grandfather->_col = RED;
parent->_col = BLACK;
}
break; //子树旋转后,该子树的根变成了黑色,无需继续往上进行处理
}
}
}
_root->_col = BLACK; //根结点的颜色为黑色(可能被情况一变成了红色,需要变回黑色)
return make_pair(newnode, true); //插入成功
}
//删除函数
bool Erase(const K& key)
{
//用于遍历二叉树
Node* parent = nullptr;
Node* cur = _root;
//用于标记实际的待删除结点及其父结点
Node* delParentPos = nullptr;
Node* delPos = nullptr;
while (cur)
{
if (key < cur->_kv.first) //所给key值小于当前结点的key值
{
//往该结点的左子树走
parent = cur;
cur = cur->_left;
}
else if (key > cur->_kv.first) //所给key值大于当前结点的key值
{
//往该结点的右子树走
parent = cur;
cur = cur->_right;
}
else //找到了待删除结点
{
if (cur->_left == nullptr) //待删除结点的左子树为空
{
if (cur == _root) //待删除结点是根结点
{
_root = _root->_right; //让根结点的右子树作为新的根结点
if (_root)
{
_root->_parent = nullptr;
_root->_col = BLACK; //根结点为黑色
}
delete cur; //删除原根结点
return true;
}
else
{
delParentPos = parent; //标记实际删除结点的父结点
delPos = cur; //标记实际删除的结点
}
break; //进行红黑树的调整以及结点的实际删除
}
else if (cur->_right == nullptr) //待删除结点的右子树为空
{
if (cur == _root) //待删除结点是根结点
{
_root = _root->_left; //让根结点的左子树作为新的根结点
if (_root)
{
_root->_parent = nullptr;
_root->_col = BLACK; //根结点为黑色
}
delete cur; //删除原根结点
return true;
}
else
{
delParentPos = parent; //标记实际删除结点的父结点
delPos = cur; //标记实际删除的结点
}
break; //进行红黑树的调整以及结点的实际删除
}
else //待删除结点的左右子树均不为空
{
//替换法删除
//寻找待删除结点右子树当中key值最小的结点作为实际删除结点
Node* minParent = cur;
Node* minRight = cur->_right;
while (minRight->_left)
{
minParent = minRight;
minRight = minRight->_left;
}
cur->_kv.first = minRight->_kv.first; //将待删除结点的key改为minRight的key
cur->_kv.second = minRight->_kv.second; //将待删除结点的value改为minRight的value
delParentPos = minParent; //标记实际删除结点的父结点
delPos = minRight; //标记实际删除的结点
break; //进行红黑树的调整以及结点的实际删除
}
}
}
if (delPos == nullptr) //delPos没有被修改过,说明没有找到待删除结点
{
return false;
}
//记录待删除结点及其父结点(用于后续实际删除)
Node* del = delPos;
Node* delP = delParentPos;
//调整红黑树
if (delPos->_col == BLACK) //删除的是黑色结点
{
if (delPos->_left) //待删除结点有一个红色的左孩子(不可能是黑色)
{
delPos->_left->_col = BLACK; //将这个红色的左孩子变黑即可
}
else if (delPos->_right) //待删除结点有一个红色的右孩子(不可能是黑色)
{
delPos->_right->_col = BLACK; //将这个红色的右孩子变黑即可
}
else //待删除结点的左右均为空
{
while (delPos != _root) //可能一直调整到根结点
{
if (delPos == delParentPos->_left) //待删除结点是其父结点的左孩子
{
Node* brother = delParentPos->_right; //兄弟结点是其父结点的右孩子
//情况一:brother为红色
if (brother->_col == RED)
{
delParentPos->_col = RED;
brother->_col = BLACK;
RotateL(delParentPos);
//需要继续处理
brother = delParentPos->_right; //更新brother(否则在本循环中执行其他情况的代码会出错)
}
//情况二:brother为黑色,且其左右孩子都是黑色结点或为空
if (((brother->_left == nullptr) || (brother->_left->_col == BLACK))
&& ((brother->_right == nullptr) || (brother->_right->_col == BLACK)))
{
brother->_col = RED;
if (delParentPos->_col == RED)
{
delParentPos->_col = BLACK;
break;
}
//需要继续处理
delPos = delParentPos;
delParentPos = delPos->_parent;
}
else
{
//情况三:brother为黑色,且其左孩子是红色结点,右孩子是黑色结点或为空
if ((brother->_right == nullptr) || (brother->_right->_col == BLACK))
{
brother->_left->_col = BLACK;
brother->_col = RED;
RotateR(brother);
//需要继续处理
brother = delParentPos->_right; //更新brother(否则执行下面情况四的代码会出错)
}
//情况四:brother为黑色,且其右孩子是红色结点
brother->_col = delParentPos->_col;
delParentPos->_col = BLACK;
brother->_right->_col = BLACK;
RotateL(delParentPos);
break; //情况四执行完毕后调整一定结束
}
}
else //delPos == delParentPos->_right //待删除结点是其父结点的左孩子
{
Node* brother = delParentPos->_left; //兄弟结点是其父结点的左孩子
//情况一:brother为红色
if (brother->_col == RED) //brother为红色
{
delParentPos->_col = RED;
brother->_col = BLACK;
RotateR(delParentPos);
//需要继续处理
brother = delParentPos->_left; //更新brother(否则在本循环中执行其他情况的代码会出错)
}
//情况二:brother为黑色,且其左右孩子都是黑色结点或为空
if (((brother->_left == nullptr) || (brother->_left->_col == BLACK))
&& ((brother->_right == nullptr) || (brother->_right->_col == BLACK)))
{
brother->_col = RED;
if (delParentPos->_col == RED)
{
delParentPos->_col = BLACK;
break;
}
//需要继续处理
delPos = delParentPos;
delParentPos = delPos->_parent;
}
else
{
//情况三:brother为黑色,且其右孩子是红色结点,左孩子是黑色结点或为空
if ((brother->_left == nullptr) || (brother->_left->_col == BLACK))
{
brother->_right->_col = BLACK;
brother->_col = RED;
RotateL(brother);
//需要继续处理
brother = delParentPos->_left; //更新brother(否则执行下面情况四的代码会出错)
}
//情况四:brother为黑色,且其左孩子是红色结点
brother->_col = delParentPos->_col;
delParentPos->_col = BLACK;
brother->_left->_col = BLACK;
RotateR(delParentPos);
break; //情况四执行完毕后调整一定结束
}
}
}
}
}
//进行实际删除
if (del->_left == nullptr) //实际删除结点的左子树为空
{
if (del == delP->_left) //实际删除结点是其父结点的左孩子
{
delP->_left = del->_right;
if (del->_right)
del->_right->_parent = delP;
}
else //实际删除结点是其父结点的右孩子
{
delP->_right = del->_right;
if (del->_right)
del->_right->_parent = delP;
}
}
else //实际删除结点的右子树为空
{
if (del == delP->_left) //实际删除结点是其父结点的左孩子
{
delP->_left = del->_left;
if (del->_left)
del->_left->_parent = delP;
}
else //实际删除结点是其父结点的右孩子
{
delP->_right = del->_left;
if (del->_left)
del->_left->_parent = delP;
}
}
delete del; //实际删除结点
return true;
}
private:
//拷贝树
Node* _Copy(Node* root, Node* parent)
{
if (root == nullptr)
{
return nullptr;
}
Node* copyNode = new Node(root->_data);
copyNode->_parent = parent;
copyNode->_left = _Copy(root->_left, copyNode);
copyNode->_right = _Copy(root->_right, copyNode);
return copyNode;
}
//析构函数子函数
void _Destroy(Node* root)
{
if (root == nullptr)
{
return;
}
_Destroy(root->_left);
_Destroy(root->_right);
delete root;
}
//左单旋
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
Node* parentParent = parent->_parent;
//建立subRL与parent之间的联系
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
//建立parent与subR之间的联系
subR->_left = parent;
parent->_parent = subR;
//建立subR与parentParent之间的联系
if (parentParent == nullptr)
{
_root = subR;
_root->_parent = nullptr;
}
else
{
if (parent == parentParent->_left)
{
parentParent->_left = subR;
}
else
{
parentParent->_right = subR;
}
subR->_parent = parentParent;
}
}
//右单旋
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* parentParent = parent->_parent;
//建立subLR与parent之间的联系
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
//建立parent与subL之间的联系
subL->_right = parent;
parent->_parent = subL;
//建立subL与parentParent之间的联系
if (parentParent == nullptr)
{
_root = subL;
_root->_parent = nullptr;
}
else
{
if (parent == parentParent->_left)
{
parentParent->_left = subL;
}
else
{
parentParent->_right = subL;
}
subL->_parent = parentParent;
}
}
//左右双旋
void RotateLR(Node* parent)
{
RotateL(parent->_left);
RotateR(parent);
}
//右左双旋
void RotateRL(Node* parent)
{
RotateR(parent->_right);
RotateL(parent);
}
Node* _root; //红黑树的根结点
};
二、红黑树再设计
1. 重新设计 RBTree 的模板参数
之前我们的RBTree模板参数是Key-Value模型,但此时我们不得不再考虑设计新的模板参数,因为STL中set、map都是适配红黑树,那么同一个RBTree模板如何同时适配set(Key模型)、map(Key-Value模型)呢?
template<class K, class T>
class RBTree
为什么要设计为K,T模板?
根据是set 还是 map,T有两种可能: key 或 pair<K, T>,所以我们需要第一个模板参数K,它绝对是Key。
设计成K,T是为了适配 find 、erase函数,因为 find 函数需要参数Key,如果以之前的模板参数设计,set调用时很方便,直接传递Key;而map只能传递pair键值对,那么 find 内部还要根据上层是set还是map,来解析传递的模板参数是裸露的Key还是在键值对中的Key,但是对于底层红黑树来说,它并不知道上层容器是map还是set,所以如果不修改模板参数,那么这无疑加重了红黑树中 find 的设计难度!
所以,set、map都后退一步,全都以统一的模板参数适配RBTree,set多传递一个模板参数Key、map将V修改为pair<K, V>,这样set、map就可以协调统一的适配RBTree,可以说set是跟着map “陪跑”,因为set、map共用的红黑树底层
- set容器:K和T都代表键值Key
- map容器:K代表键值Key,T代表由Key和Value构成的键值对
//set
RBTree<K, K> _t;
//map
RBTree<K, pair<K, V>> _t;
在红黑树中 typedef RBTreeNode<T> Node,红黑树节点直接接收参数T,更改后代码如下:
//红黑树结点的定义
template<class T>
struct RBTreeNode
{
//三叉链
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
//存储的数据
T _data;
//结点的颜色
int _col; //红/黑
//构造函数
RBTreeNode(const T& data)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
, _col(RED)
{}
};
2. 仿函数模板参数
红黑树重新设计模板参数后,节点存储的是T类型,这个T即可能是Key,也可能是pair<Key, Value>键值对,那么如果在find函数内进行节点的Key大小比较时,如果正确获取Key用来比较大小呢?
底层红黑树的插入比较时,因为T的类型不确定,所以我们可以模仿list模拟实现时使用的仿函数,来比较大小,但是这里我们不直接在仿函数内比较大小,而是使用 KeyOfT 类,用它创建一个类对象,使用仿函数来获取 T 中 Key,而不是直接进行比较!
对于set,T 就是key;对于map,T是pair,所以要返回 pair 的 first
为什么不将仿函数功能复合,直接设计成比大小返回bool类型?
因为可能有指针等类型,不能按平常的比较来比较,并且在STL的set、map设计中,还有一个用户传递的模板参数compare,它的仿函数是专门用来比较的。
KeyOfT是红黑树内部用的,两个仿函数各干各的活。如果都交给一个仿函数,那么要排列组合设计很多种类型比较。
当底层红黑树需要进行两个结点之间键值的比较时,都会通过传入的仿函数来获取相应结点的键值,然后再进行比较,下面以红黑树的查找函数为例:
//查找函数
iterator Find(const K& key)
{
KeyOfT kot;
Node* cur = _root;
while (cur)
{
if (key < kot(cur->_data)) //key值小于该结点的值
{
cur = cur->_left; //在该结点的左子树当中查找
}
else if (key > kot(cur->_data)) //key值大于该结点的值
{
cur = cur->_right; //在该结点的右子树当中查找
}
else //找到了目标结点
{
return iterator(cur); //返回该结点
}
}
return end(); //查找失败
}
3. 正向迭代器
构造
红黑树的迭代器封装红黑树节点指针即可(同list模拟实现,迭代器传入三个模板参数是为了更好的设计const迭代器)
//正向迭代器
template<class T, class Ref, class Ptr>
struct __TreeIterator
{
typedef RBTreeNode<T> Node; //结点的类型
typedef __TreeIterator<T, Ref, Ptr> Self; //正向迭代器的类型
Node* _node; //正向迭代器所封装结点的指针
//构造函数
__TreeIterator(Node* node)
:_node(node) //根据所给结点指针构造一个正向迭代器
{}
};
operator*()
当对正向迭代器进行解引用操作时,我们直接返回 对应结点数据的引用
Ref operator*()
{
return _node->_data; //返回结点数据的引用
}
operator->()
当对正向迭代器进行->
操作时,我们直接返回对应结点数据的指针
Ptr operator->()
{
return &_node->_data; //返回结点数据的指针
}
operator!=()
operator重载!= 和 ==,比较时直接比较Node*即可(地址最容易比较是否相等)
//判断两个正向迭代器是否不同
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* left = _node->_right;
while (left->_left)
{
left = left->_left;
}
_node = left; //++后变为该结点
}
else //结点的右子树为空
{
//寻找孩子不在父亲右的祖先
Node* cur = _node;
Node* parent = cur->_parent;
while (parent&&cur == parent->_right)
{
cur = parent;
parent = parent->_parent;
}
_node = parent; //++后变为该结点
}
return *this;
}
operator--()
- 如果当前结点的左子树不为空,则
--
操作后应该找到其左子树当中的最右结点。 - 如果当前结点的左子树为空,则
--
操作后应该在该结点的祖先结点中,找到孩子不在父亲左的祖先
//前置--
Self operator--()
{
if (_node->_left) //结点的左子树不为空
{
//寻找该结点左子树当中的最右结点
Node* right = _node->_left;
while (right->_right)
{
right = right->_right;
}
_node = right; //--后变为该结点
}
else //结点的左子树为空
{
//寻找孩子不在父亲左的祖先
Node* cur = _node;
Node* parent = cur->_parent;
while (parent&&cur == parent->_left)
{
cur = parent;
parent = parent->_parent;
}
_node = parent; //--后变为该结点
}
return *this;
}
正向迭代器代码
template<class T, class Ref, class Ptr>
struct __TreeIterator
{
typedef RBTreeNode<T> Node;
typedef __TreeIterator<T, Ref, Ptr> Self;
/*不管此时__TreeIterator是普通迭代器还是const迭代器,
我们typedef的Iterator类型都是普通的迭代器*/
typedef __TreeIterator<T, T&, T*> Iterator;
//成员变量
Node* _node;
//构造函数
__TreeIterator(Node* node)
:_node(node)
{}
//当__TreeIterator是const迭代器时,这里用普通迭代器构造const迭代器,这是一个构造函数
//当_TreeIterator是普通迭代器时,这里用普通迭代器构造const迭代器,这是一个拷贝构造函数
__TreeIterator(const Iterator& it)
:_node(it._node)
{}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
Self& operator--()
{
//左子树不为空
if (_node->_left)
{
//找左子树的最右节点
Node* subRight = _node->_left;
while (subRight->_right)
{
subRight = subRight->_right;
}
_node = subRight;
}
else //左子树为空,找孩子不在父亲左的祖先
{
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && cur == parent->_left)
{
cur = parent;
parent = cur->_parent;
}
_node = parent;
}
return *this;
}
Self& operator++()
{
//如果右树不为空
if (_node->_right)
{
// 右树的最左节点(最小节点)
Node* subLeft = _node->_right;
while (subLeft->_left)
{
subLeft = subLeft->_left;
}
_node = subLeft;
}
else //右树为空
{
Node* cur = _node;
Node* parent = cur->_parent;
// 找孩子是父亲左的那个祖先节点,就是下一个要访问的节点
while (parent)
{
if (cur == parent->_left) break;
else
{
cur = cur->_parent;
parent = parent->_parent;
}
}
_node = parent;
}
return *this;
}
bool operator!=(const Self& s) const
{
return _node != s._node;
}
bool operator==(const Self& s) const
{
//拿地址来比较
return _node == s._node;
}
};
4. 反向迭代器
在反向迭代器当中只有一个成员变量,那就是反向迭代器封装的正向迭代器。反向迭代器的中成员函数,都是通过调用正向迭代器对应的函数来完成相应功能的
构造
同list模拟实现,反向迭代器直接适配正向迭代器
#pragma once
template<class Iterator, class Ref, class Ptr>
struct ReverseIterator
{
typedef ReverseIterator<Iterator, Ref, Ptr> Self; //反向迭代器自身类型
//封装普通迭代器
Iterator _it;
//构造
ReverseIterator(Iterator it)
:_it(it)
{}
};
operator*
Ref operator* ()
{
return *_it;
}
operator->
Ptr operator->()
{
return _it.operator->();
}
operator++
适配正向迭代器,直接--即可。
Self& operator++()
{
--_it;
return *this;
}
operator--
适配正向迭代器,直接++即可
Self& operator--()
{
++_it;
return *this;
}
注意:我们实现的都是前置的++或--
operator!=
bool operator!=(const Self& s) const
{
return _it != s._it;
}
bool operator==(const Self& s) const
{
return _it == s._it;
}
反向迭代器代码
#pragma once
template<class Iterator, class Ref, class Ptr>
struct ReverseIterator
{
typedef ReverseIterator<Iterator, Ref, Ptr> Self; //反向迭代器自身类型
//封装普通迭代器
Iterator _it;
//构造
ReverseIterator(Iterator it)
:_it(it)
{}
Ref operator* ()
{
return *_it;
}
Ptr operator->()
{
return _it.operator->();
}
Self& operator++()
{
--_it;
return *this;
}
Self& operator--()
{
++_it;
return *this;
}
bool operator!=(const Self& s) const
{
return _it != s._it;
}
bool operator==(const Self& s) const
{
return _it == s._it;
}
};
5. 红黑树主体
我们需要在红黑树的实现当中进行迭代器类型的typedef。需要注意的是,为了让外部能够使用typedef后的正向迭代器类型iterator,我们需要在public区域进行typedef
begin()、end()、
- begin函数返回中序序列当中第一个结点的正向迭代器,即最左结点。
- end函数返回中序序列当中最后一个结点下一个位置的正向迭代器,这里直接用空指针构造一个正向迭代器
template<class K, class T, class KeyOfT>
class RBTree
{
typedef RBTreeNode<T> Node; //结点的类型
public:
typedef __TreeIterator<T, T&, T*> iterator;
typedef __TreeIterator<T, const T&, const T*> const_iterator;
iterator begin()
{
//寻找最左结点
Node* left = _root;
while (left&&left->_left)
{
left = left->_left;
}
//返回最左结点的正向迭代器
return iterator(left);
}
iterator end()
{
//返回由nullptr构造得到的正向迭代器(不严谨)
return iterator(nullptr);
}
const_iterator begin() const
{
Node* leftMin = _root;
while (leftMin && leftMin->_left)
{
leftMin = leftMin->_left;
}
return iterator(leftMin);
}
const_iterator end() const
{
return iterator(nullptr);
}
private:
Node* _root; //红黑树的根结点
};
rbegin()、rend()
- rbegin函数返回中序序列当中最后一个结点的反向迭代器,即最右结点。
- rend函数返回中序序列当中第一个结点前一个位置的反向迭代器,这里直接用空指针构造一个反向迭代器。
template<class K, class T, class KeyOfT>
struct RBTree
{
typedef RBTreeNode<T> Node;
public:
typedef __TreeIterator<T, T&, T*> iterator;
typedef __TreeIterator<T, const T&, const T*> const_iterator;
typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;
reverse_iterator rbegin()
{
Node* right = _root;
while (right && right->_right)
{
right = right->_right;
}
return reverse_iterator(iterator(right));
}
reverse_iterator rend()
{
return reverse_iterator(iterator(nullptr));
}
const_reverse_iterator rbegin() const
{
Node* right = _root;
while (right && right->_right)
{
right = right->_right;
}
return reverse_iterator(iterator(right));
}
const_reverse_iterator rend() const
{
return reverse_iterator(iterator(nullptr));
}
private:
Node* _root; //红黑树的根结点
};
insert 返回值
pair<iterator, bool> insert(const K& key);
- 如果插入成功,那么返回新插入的节点的迭代器与 true 构成的 pair
- 如果插入失败(相应的Key已经存在),那么返回已经存在的 Key 对应的节点迭代器与 false构成的pair
所以在红黑树主体部分,如果 insert 内部要返回 bool 类型时,我们 make_pair 返回 pair<iterator, bool>类型即可
//插入函数
pair<iterator, bool> Insert(const T& data)
{
if (_root == nullptr)
{
_root = new Node(data);
_root->_col = BLACK;
return make_pair(iterator(_root), true);
}
Node* parent = nullptr;
Node* cur = _root;
KeyOfT kot;
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(iterator(cur), false);
}
}
cur = new Node(data);
cur->_col = RED;
Node* newnode = cur;
if (kot(parent->_data) < kot(data))
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent;
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
// u存在且为红
if (uncle && uncle->_col == RED)
{
// 变色
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续向上处理
cur = grandfather;
parent = cur->_parent;
}
else // u不存在 或 存在且为黑
{
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;
}
}
else // parent == grandfather->_right
{
Node* uncle = grandfather->_left;
// u存在且为红
if (uncle && uncle->_col == RED)
{
// 变色
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续向上处理
cur = grandfather;
parent = cur->_parent;
}
else
{
if (cur == parent->_right)
{
// g
// p
// c
RotateL(grandfather);
grandfather->_col = RED;
parent->_col = BLACK;
}
else
{
// g
// p
// c
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return make_pair(iterator(newnode), true);
}
find返回值
同理,在返回处 make_pair 即可。
注意:如果没找到需返回end()
iterator Find(const K& key)
{
Node* cur = _root;
KeyOfT kot;
while (cur)
{
if (kot(cur->_data) < key)
{
cur = cur->_right;
}
else if (kot(cur->_data) > key)
{
cur = cur->_left;
}
else
{
return iterator(cur);
}
}
return end();
}
STL标准库设计
上述所实现的迭代器是有缺陷的,因为理论上我们对end()
位置的正向迭代器进行--
操作后,应该得到最后一个结点的正向迭代器,但我们实现end()
时,是直接返回由nullptr构造得到的正向迭代器的,因此上述实现的代码无法完成此操作。
下面我们来看看C++SLT库当中的实现逻辑:
C++STL库当中实现红黑树时,在红黑树的根结点处增加了一个头结点,该头结点的左指针指向红黑树当中的最左结点,右指针指向红黑树当中的最右结点,父指针指向红黑树的根结点。
在该结构下,实现begin()时,直接用头结点的左孩子构造一个正向迭代器即可,实现rbegin()时,直接用头结点的右孩子构造一个反向迭代器即可(实际是先用该结点构造一个正向迭代器,再用正向迭代器构造出反向迭代器),而实现end()和rend()时,直接用头结点构造出正向和反向迭代器即可。此后,通过对逻辑的控制,就可以实现end()进行--操作后得到最后一个结点的正向迭代器。
但实现该结构需要更改当前很多函数的逻辑,例如插入结点时,若插入到了红黑树最左结点的左边,或最右结点的右边,此时需要更新头结点左右指针的指向
6. 再设计后完整的RBTree代码
#pragma once
#include<iostream>
#include "ReverseIterator.h"
using namespace std;
enum Colour
{
RED,
BLACK
};
template<class T>
struct RBTreeNode
{
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Colour _col;
RBTreeNode(const T& data)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
, _col(RED)
{}
};
// set->RBTree<K, K, SetKeyOfT> _t;
// map->RBTree<K, pair<K, V>, MapKeyOfT> _t;
template<class K, class T, class KeyOfT>
struct RBTree
{
typedef RBTreeNode<T> Node;
public:
typedef __TreeIterator<T, T&, T*> iterator;
typedef __TreeIterator<T, const T&, const T*> const_iterator;
typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;
iterator begin()
{
Node* leftMin = _root;
while (leftMin && leftMin->_left)
{
leftMin = leftMin->_left;
}
return iterator(leftMin);
}
iterator end()
{
return iterator(nullptr);
}
const_iterator begin() const
{
Node* leftMin = _root;
while (leftMin && leftMin->_left)
{
leftMin = leftMin->_left;
}
return iterator(leftMin);
}
const_iterator end() const
{
return iterator(nullptr);
}
reverse_iterator rbegin()
{
Node* right = _root;
while (right && right->_right)
{
right = right->_right;
}
return reverse_iterator(iterator(right));
}
reverse_iterator rend()
{
return reverse_iterator(iterator(nullptr));
}
const_reverse_iterator rbegin() const
{
Node* right = _root;
while (right && right->_right)
{
right = right->_right;
}
return reverse_iterator(iterator(right));
}
const_reverse_iterator rend() const
{
return reverse_iterator(iterator(nullptr));
}
//构造函数
RBTree()
:_root(nullptr)
{}
//拷贝构造
RBTree(const RBTree<K, T, KeyOfT>& t)
{
_root = _Copy(t._root, nullptr);
}
//赋值运算符重载(现代写法)
RBTree<K, T, KeyOfT>& operator=(RBTree<K, T, KeyOfT> t)
{
swap(_root, t._root);
return *this; //支持连续赋值
}
//析构函数
~RBTree()
{
_Destroy(_root);
_root = nullptr;
}
iterator Find(const K& key)
{
Node* cur = _root;
KeyOfT kot;
while (cur)
{
if (kot(cur->_data) < key)
{
cur = cur->_right;
}
else if (kot(cur->_data) > key)
{
cur = cur->_left;
}
else
{
return iterator(cur);
}
}
return end();
}
//插入函数
pair<iterator, bool> Insert(const T& data)
{
if (_root == nullptr)
{
_root = new Node(data);
_root->_col = BLACK;
return make_pair(iterator(_root), true);
}
Node* parent = nullptr;
Node* cur = _root;
KeyOfT kot;
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(iterator(cur), false);
}
}
cur = new Node(data);
cur->_col = RED;
Node* newnode = cur;
if (kot(parent->_data) < kot(data))
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent;
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
// u存在且为红
if (uncle && uncle->_col == RED)
{
// 变色
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续向上处理
cur = grandfather;
parent = cur->_parent;
}
else // u不存在 或 存在且为黑
{
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;
}
}
else // parent == grandfather->_right
{
Node* uncle = grandfather->_left;
// u存在且为红
if (uncle && uncle->_col == RED)
{
// 变色
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续向上处理
cur = grandfather;
parent = cur->_parent;
}
else
{
if (cur == parent->_right)
{
// g
// p
// c
RotateL(grandfather);
grandfather->_col = RED;
parent->_col = BLACK;
}
else
{
// g
// p
// c
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return make_pair(iterator(newnode), true);
}
//删除函数
bool Erase(const K& key)
{
KeyOfT kot;
//用于遍历二叉树
Node* parent = nullptr;
Node* cur = _root;
//用于标记实际的待删除结点及其父结点
Node* delParentPos = nullptr;
Node* delPos = nullptr;
while (cur)
{
if (key < kot(cur->_data)) //所给key值小于当前结点的key值
{
//往该结点的左子树走
parent = cur;
cur = cur->_left;
}
else if (key > kot(cur->_data)) //所给key值大于当前结点的key值
{
//往该结点的右子树走
parent = cur;
cur = cur->_right;
}
else //找到了待删除结点
{
if (cur->_left == nullptr) //待删除结点的左子树为空
{
if (cur == _root) //待删除结点是根结点
{
_root = _root->_right; //让根结点的右子树作为新的根结点
if (_root)
{
_root->_parent = nullptr;
_root->_col = BLACK; //根结点为黑色
}
delete cur; //删除原根结点
return true;
}
else
{
delParentPos = parent; //标记实际删除结点的父结点
delPos = cur; //标记实际删除的结点
}
break; //进行红黑树的调整以及结点的实际删除
}
else if (cur->_right == nullptr) //待删除结点的右子树为空
{
if (cur == _root) //待删除结点是根结点
{
_root = _root->_left; //让根结点的左子树作为新的根结点
if (_root)
{
_root->_parent = nullptr;
_root->_col = BLACK; //根结点为黑色
}
delete cur; //删除原根结点
return true;
}
else
{
delParentPos = parent; //标记实际删除结点的父结点
delPos = cur; //标记实际删除的结点
}
break; //进行红黑树的调整以及结点的实际删除
}
else //待删除结点的左右子树均不为空
{
//替换法删除
//寻找待删除结点右子树当中key值最小的结点作为实际删除结点
Node* minParent = cur;
Node* minRight = cur->_right;
while (minRight->_left)
{
minParent = minRight;
minRight = minRight->_left;
}
cur->_data = minRight->_data; //将待删除结点的_data改为minRight的_data
delParentPos = minParent; //标记实际删除结点的父结点
delPos = minRight; //标记实际删除的结点
break; //进行红黑树的调整以及结点的实际删除
}
}
}
if (delPos == nullptr) //delPos没有被修改过,说明没有找到待删除结点
{
return false;
}
//记录待删除结点及其父结点(用于后续实际删除)
Node* del = delPos;
Node* delP = delParentPos;
//调整红黑树
if (delPos->_col == BLACK) //删除的是黑色结点
{
if (delPos->_left) //待删除结点有一个红色的左孩子(不可能是黑色)
{
delPos->_left->_col = BLACK; //将这个红色的左孩子变黑即可
}
else if (delPos->_right) //待删除结点有一个红色的右孩子(不可能是黑色)
{
delPos->_right->_col = BLACK; //将这个红色的右孩子变黑即可
}
else //待删除结点的左右均为空
{
while (delPos != _root) //可能一直调整到根结点
{
if (delPos == delParentPos->_left) //待删除结点是其父结点的左孩子
{
Node* brother = delParentPos->_right; //兄弟结点是其父结点的右孩子
//情况一:brother为红色
if (brother->_col == RED)
{
delParentPos->_col = RED;
brother->_col = BLACK;
RotateL(delParentPos);
//需要继续处理
brother = delParentPos->_right; //更新brother(否则在本循环中执行其他情况的代码会出错)
}
//情况二:brother为黑色,且其左右孩子都是黑色结点或为空
if (((brother->_left == nullptr) || (brother->_left->_col == BLACK))
&& ((brother->_right == nullptr) || (brother->_right->_col == BLACK)))
{
brother->_col = RED;
if (delParentPos->_col == RED)
{
delParentPos->_col = BLACK;
break;
}
//需要继续处理
delPos = delParentPos;
delParentPos = delPos->_parent;
}
else
{
//情况三:brother为黑色,且其左孩子是红色结点,右孩子是黑色结点或为空
if ((brother->_right == nullptr) || (brother->_right->_col == BLACK))
{
brother->_left->_col = BLACK;
brother->_col = RED;
RotateR(brother);
//需要继续处理
brother = delParentPos->_right; //更新brother(否则执行下面情况四的代码会出错)
}
//情况四:brother为黑色,且其右孩子是红色结点
brother->_col = delParentPos->_col;
delParentPos->_col = BLACK;
brother->_right->_col = BLACK;
RotateL(delParentPos);
break; //情况四执行完毕后调整一定结束
}
}
else //delPos == delParentPos->_right //待删除结点是其父结点的左孩子
{
Node* brother = delParentPos->_left; //兄弟结点是其父结点的左孩子
//情况一:brother为红色
if (brother->_col == RED) //brother为红色
{
delParentPos->_col = RED;
brother->_col = BLACK;
RotateR(delParentPos);
//需要继续处理
brother = delParentPos->_left; //更新brother(否则在本循环中执行其他情况的代码会出错)
}
//情况二:brother为黑色,且其左右孩子都是黑色结点或为空
if (((brother->_left == nullptr) || (brother->_left->_col == BLACK))
&& ((brother->_right == nullptr) || (brother->_right->_col == BLACK)))
{
brother->_col = RED;
if (delParentPos->_col == RED)
{
delParentPos->_col = BLACK;
break;
}
//需要继续处理
delPos = delParentPos;
delParentPos = delPos->_parent;
}
else
{
//情况三:brother为黑色,且其右孩子是红色结点,左孩子是黑色结点或为空
if ((brother->_left == nullptr) || (brother->_left->_col == BLACK))
{
brother->_right->_col = BLACK;
brother->_col = RED;
RotateL(brother);
//需要继续处理
brother = delParentPos->_left; //更新brother(否则执行下面情况四的代码会出错)
}
//情况四:brother为黑色,且其左孩子是红色结点
brother->_col = delParentPos->_col;
delParentPos->_col = BLACK;
brother->_left->_col = BLACK;
RotateR(delParentPos);
break; //情况四执行完毕后调整一定结束
}
}
}
}
}
//进行实际删除
if (del->_left == nullptr) //实际删除结点的左子树为空
{
if (del == delP->_left) //实际删除结点是其父结点的左孩子
{
delP->_left = del->_right;
if (del->_right)
del->_right->_parent = delP;
}
else //实际删除结点是其父结点的右孩子
{
delP->_right = del->_right;
if (del->_right)
del->_right->_parent = delP;
}
}
else //实际删除结点的右子树为空
{
if (del == delP->_left) //实际删除结点是其父结点的左孩子
{
delP->_left = del->_left;
if (del->_left)
del->_left->_parent = delP;
}
else //实际删除结点是其父结点的右孩子
{
delP->_right = del->_left;
if (del->_left)
del->_left->_parent = delP;
}
}
delete del; //实际删除结点
return true;
}
private:
//拷贝树
Node* _Copy(Node* root, Node* parent)
{
if (root == nullptr)
{
return nullptr;
}
Node* copyNode = new Node(root->_data);
copyNode->_parent = parent;
copyNode->_left = _Copy(root->_left, copyNode);
copyNode->_right = _Copy(root->_right, copyNode);
return copyNode;
}
//析构函数子函数
void _Destroy(Node* root)
{
if (root == nullptr)
{
return;
}
_Destroy(root->_left);
_Destroy(root->_right);
delete root;
}
//左单旋
void RotateL(Node* parent)
{
++_rotateCount;
Node* cur = parent->_right;
Node* curleft = cur->_left;
parent->_right = curleft;
if (curleft)
{
curleft->_parent = parent;
}
cur->_left = parent;
Node* ppnode = parent->_parent;
parent->_parent = cur;
if (parent == _root)
{
_root = cur;
cur->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
{
ppnode->_left = cur;
}
else
{
ppnode->_right = cur;
}
cur->_parent = ppnode;
}
}
//右单旋
void RotateR(Node* parent)
{
++_rotateCount;
Node* cur = parent->_left;
Node* curright = cur->_right;
parent->_left = curright;
if (curright)
curright->_parent = parent;
Node* ppnode = parent->_parent;
cur->_right = parent;
parent->_parent = cur;
if (ppnode == nullptr)
{
_root = cur;
cur->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
{
ppnode->_left = cur;
}
else
{
ppnode->_right = cur;
}
cur->_parent = ppnode;
}
}
//检查红黑树颜色
bool CheckColour(Node* root, int blacknum, int benchmark)
{
if (root == nullptr)
{
if (blacknum != benchmark)
return false;
return true;
}
if (root->_col == BLACK)
{
++blacknum;
}
if (root->_col == RED && root->_parent && root->_parent->_col == RED)
{
cout << root->_kv.first << "出现连续红色节点" << endl;
return false;
}
return CheckColour(root->_left, blacknum, benchmark)
&& CheckColour(root->_right, blacknum, benchmark);
}
bool IsBalance()
{
return IsBalance(_root);
}
bool IsBalance(Node* root)
{
if (root == nullptr)
return true;
if (root->_col != BLACK)
{
return false;
}
// 基准值
int benchmark = 0;
Node* cur = _root;
while (cur)
{
if (cur->_col == BLACK)
++benchmark;
cur = cur->_left;
}
return CheckColour(root, 0, benchmark);
}
int Height()
{
return Height(_root);
}
int Height(Node* root)
{
if (root == nullptr)
return 0;
int leftHeight = Height(root->_left);
int rightHeight = Height(root->_right);
return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
private:
Node* _root = nullptr;
public:
int _rotateCount = 0;
};
三、set、map封装
1. set基础封装
#include "RBTree.h"
namespace my_set
{
template<class K>
class set
{
struct SetKeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
public:
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
typedef typename RBTree<K, K, SetKeyOfT>::reverse_iterator reverse_iterator;
iterator begin()
{
return _t.begin();
}
iterator end()
{
return _t.end();
}
reverse_iterator rbegin()
{
return _t.rbegin();
}
reverse_iterator rend()
{
return _t.rend();
}
pair<iterator, bool> insert(const K& key)
{}
void erase(const K& key)
{}
iterator find(const K& key)
{}
private:
RBTree<K, K, SetKeyOfT> _t;
};
}
2. map基础封装
#include "RBTree.h"
namespace my_map
{
template<class K, class V>
class map
{
struct MapKeyOfT
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
public:
typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::iterator iterator;
typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::reverse_iterator reverse_iterator;
iterator begin()
{
return _t.begin();
}
iterator end()
{
return _t.end();
}
reverse_iterator rbegin()
{
return _t.rbegin();
}
reverse_iterator rend()
{
return _t.rend();
}
pair<iterator, bool> insert(const pair<K, V>& kv)
{}
V& operator[](const K& key)
{}
void erase(const K& key)
{}
iterator find(const K& key)
{}
private:
RBTree<K, pair<K, V>, MapKeyOfT> _t;
};
}
3. insert
set:
pair<iterator, bool> insert(const K& key)
{
return _t.Insert(key);
}
set 的迭代器 typedef 了红黑树的 const_iterator
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
map:
pair<iterator, bool> insert(const pair<K, V>& kv)
{
return _t.Insert(kv);
}
map 的 iterator 没有 typedef 红黑树的 const_iterator
typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::iterator iterator;
编译:
问题的引发:在封装map的operator[] 函数时,需要用到insert函数的pair<iterator, bool>返回值,但是此时 set 的返回处出现问题
C2440 “return”: 无法从“std::pair<__TreeIterator<T,T &,T *>,bool>”转换为“std::pair<__TreeIterator<T,const T &,const T *>,bool>”
摸索:
set 底层适配 RBtree 结构 ,所以 set 的 insert 调用的是 RBTree 的 insert 函数,又 RBTree 的 insert 函数返回的是 pair<iterator, bool> 类型(这里的 iterator是红黑树返回的普通迭代器类型)
(注意:如果在 set.h 文件中,此时 pair 的 iterator 类型其实是 const_iterator 类型,因为我们是根据 STL 中的 set 设计来设计我们的 set ,STL 中 set 的 iterator 其实是 const_iterator 的 typedef,是为了保证set的key不被修改,因为底层红黑树节点是靠key来构建的,一旦key被修改,那么整个树的结构就会混乱无序)
所以 set 的 insert 在 return _t.Insert 时,在 pair 的构造函数的初始化列表处会发生普通迭代器构造 const 迭代器的过程
所以我们需要在红黑树迭代器类中再手写一个构造函数,参数是普通迭代器,用来支持普通迭代器向const迭代器转换
迭代器类中,默认生成的拷贝构造就已经够用了,因为成员变量类型是Node*,是内置类型,可以浅拷贝,那么为什么还要设计迭代器的拷贝构造?
其实这里并不是拷贝构造,而是重载构造函数。当 set 的 insert 返回时,我们先来看pair类的构造函数:
此时T1类型是const_iterator
template <class T1, class T2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair()
: first(T1())
, second(T2())
{}
pair(const T1& a, const T2& b)
: first(a) 此时的参数a是普通iterator
, second(b) first是const_iterator
{}
};
我们发现,在pair 的构造函数的初始化列表处,出现了以普通迭代器构造const迭代器的过程,而我们的迭代器此时并没有专门接收迭代器类型的构造函数
所以,我们要在红黑树的迭代器类中实现一个迭代器构造函数,支持从普通迭代器转为const迭代器功能
我们如何在一个const迭代器类中获得普通迭代器类型?
在迭代器类设计时,typedef一个普通迭代器即可
//不管此时__TreeIterator是普通迭代器还是const迭代器,
//我们typedef的Iterator类型都是普通的迭代器
typedef __TreeIterator<T, T&, T*> Iterator;
不管此时__TreeIterator 是普通迭代器还是 const 迭代器,我们 typedef 的 Iterator 类型都是普通的迭代器
//当__TreeIterator是const迭代器时,这里用普通迭代器构造const迭代器,这是一个构造函数
//当_TreeIterator是普通迭代器时,这里用普通迭代器构造const迭代器,这是一个拷贝构造函数
__TreeIterator(const Iterator& it)
:_node(it._node)
{}
- 当 __TreeIterator 是const迭代器时,这里用普通迭代器构造const迭代器,这是一个构造函数,因为我们在迭代器类中已经写过构造函数了,所以还需要重载一个以迭代器为参数的构造函数
- 当 __TreeIterator 是普通迭代器时,这里用普通迭代器构造const迭代器,这是一个拷贝构造函数
4. map::operator[]
map::operator[]功能我们在map介绍时已经讲过了,返回 insert 返回的 iterator 的 second 数据的引用,即不管insert是否成功,我们都能获取Key的value的引用
V& operator[](const K& key)
{
pair<iterator, bool> ret = insert(make_pair(key, V()));
iterator it = ret.first;
return it->second;
}
5. find
调用适配的红黑树的Find函数即可
iterator find(const K& key)
{
return _t.Find(key);
}
6. erase
调用适配的红黑树的Erase函数即可
void erase(const K& key)
{
_t.Erase(key);
}
7. 测试
#include <iostream>
#include "MyMap.h"
#include "MySet.h"
int main()
{
//验证map
my_map::map<int, int> m;
m.insert(make_pair(1, 1));
m.insert(make_pair(3, 3));
m.insert(make_pair(4, 4));
m.insert(make_pair(3, 8));
m.insert(make_pair(5, 1));
my_map::map<int, int>::reverse_iterator mit = m.rbegin();
while (mit != m.rend())
{
cout << mit->first << ":" << mit->second << endl;
++mit;
}
cout << endl;
m[1] = 100;
m[99] = 120;
m[3] = 4;
for (const auto& e : m)
{
cout << e.first << ":" << e.second << endl;
}
cout << endl;
//验证set
my_set::set<int> s;
s.insert(5);
s.insert(15);
s.insert(54);
s.insert(23);
s.insert(0);
s.insert(9);
s.insert(4);
my_set::set<int>::iterator sit = s.begin();
while (sit != s.end())
{
cout << *sit << " ";
++sit;
}
cout << endl;
for (const auto& e : s)
{
cout << e << " ";
}
return 0;
}