注:该封装基于前面博客已实现红黑树,map和set封装并不难,主要还是对红黑树的理解
目录
颜色定义不更改,但是由于我们是使用一颗红黑树同时来作为封装set和map的底层结构,因此对数据类型需要进行处理,这里参考stl源码给出的解决方式是使用更高维度的泛型,因此我们也定义成更高维度的泛型,即数据类型这里我们使用T来接受va类型。
即我们不再使用KV的形式接受数据,而是用T来接受数据,T决定红黑树存什么数据。
这里和节点定义一样,我们使用T来接受数据,T决定红黑树存什么数据,对于set来说RBTree
传进来的是K,对于map来说RBTree >传进来的是pair类型。 虽然用T能解决传进来不同的数据类型,但是由于我们需要取K,对于set来说K就是K,但是,对于map来说是pair的第一个参数,所以由于无法确定T是K还是pair类型,无法准确去取出来T中的类型。
根据官方库可以发现再引进来一个模板参数KeyOfT,用来取出T中的类型,而这个KeOfT传给RBTree的,查看set和map后源码后发现KeyOfT其实是一个仿函数,用来提取T中类型的K的,因此我们就知道RBTree应该有三个模板参数,分别是K,T和KeyOfT
有了以上推论,我们可以对节点定义进行改变
- //改变红黑节点的定义,使用更高维度的泛型
- template<class T>
- struct RBTreeNode
- {
- RBTreeNode
* _left; - RBTreeNode
* _right; - RBTreeNode
* _parent; - T _data;
- color _col;
-
- //构造函数
- RBTreeNode(const T& data)
- :_left(nullptr)
- ,_right(nullptr)
- ,_parent(nullptr)
- ,_data(data)
- ,_col(RED)
- {}
- };
这里使用T来标识数据类型,因为节点可能是K类型的(set传过来的),也可能是pair类型的(map传过来的)
由于map和set都需要用到迭代器,但是两者的迭代器实际上都是封装了红黑树的迭代器,因此我们要先实现红黑树的迭代器,这里迭代器的实现和链表极其相似,因此,也是使用三个模板参数,分别代表普通类型,引用类型,指针类型,库里的实现是采用了哨兵卫的头节点的方式,但是这里并不这样做
- template<class T, class Ref, class Ptr>
- struct __RBTreeIterator
- {
- typedef RBTreeNode
Node;//方便使用节点 - typedef __RBTreeIterator
Self;//方便使用自己 - Node* _node;//节点指针
-
- //迭代器构造函数
- __RBTreeIterator(Node* node)
- :_node(node)
- {}
-
- operator*()
- {}
-
- operator->()
- {}
-
- operator++()
- {}
-
- operator++(int)
- {}
-
- operator--()
- {}
-
- operator--(int)
- {}
-
- operator!=(const Self& s) const
- {}
-
- operator==(const Self& s) const
- {}
-
- };
和链表迭代器的实现基本一致,将迭代器的基本功能实现
由于迭代器访问的顺序是按照二叉平衡搜索树的中序的顺序访问的,因此我们也不能坏这个规则。
按中序访问的思路,左子树->根->右子树:
begin应该返回中序的第一个元素,即需要去找二叉平衡搜索树的最左节点:
- iterator Begin()
- {
- Node* subleft = _root;
- while (subleft && subleft->_left)
- {
- subleft = subleft->_left;
- }
-
- return iterator(subleft);
- }
由于迭代器是自己实现的类,因此应该用迭代器创建对象并返回
end()应该返回的是nullptr,因为最后遍历完成后应该是遍历到最右节点的nullptr节点
- iterator End()
- {
- return iterator(nullptr);
- }
直接用迭代器创建一个对象并传nullptr
和链表一样,operator*返回节点中的数据operator->返回节点数据的地址(原因已在链表迭代器实现已解释,不做过多赘述)
- Ref operator*()
- {
- return _node->_data;
- }
-
- Ptr operator->()
- {
- return &_node->_data;
- }
由于begin(),是按照中序的方式访问的,++可以分为两种情况,当右子树不存在为空时,找孩子是祖先的左的那个祖先节点,当右子树存在不为空时,找右子树的最左节点
有如下图红黑树:

一开始begin()迭代器应该位于节点为1处,当我们要++遍历这颗红黑树时:
由于1的右子树不为空,找右子树的最左节点,最左节点为空,则++以后访问到是6,由于6的右子树为空,再++应该去找孩子是祖先的左的那个祖先节点,此时找到就是节点为8的祖先节点,此时发现,这就已经按中序的方式运行起来了
++迭代器的实现方式如下代码:
- Self& operator++()
- {
- if (_node->_right == nullptr)
- {
- Node* cur = _node;
- Node* parent = cur->_parent;
- while (parent && parent->_right == cur)
- {
- cur = parent;
- parent = parent->_parent;
- }
-
- _node = parent;
- }
- else
- {
- Node* subleft = _node->_right;
- while (subleft->_left)
- {
- subleft = subleft->_left;
- }
-
- _node = subleft;
- }
-
- return *this;
- }
-
- Self operator++(int)
- {
- Self tmp(*this);
- ++(*this);
-
- return tmp;
- }
由于begin(),是按照中序的方式访问的,--可以分为两种情况,当左子树不存在为空时,找孩子是祖先的右的那个祖先节点,当左子树存在不为空时,找左子树的最右节点
以下图红黑树为例:

假设此时迭代器已经遍历到节点为11的地方:
当我们要--遍历红黑树时,由于11的左子树不存在为空,往上找孩子是祖先的右的祖先节点,我发现11就是8的右,于是迭代器访问的是节点8的祖先节点,再次--,此时节点8的左子树存在不为空,找左子树的最右节点,此时节点6是1的最右节点,因此找到的节点是节点6,此时,发现已经是在按中序的方式遍历了
--的迭代器的实现代码如下:
- Self& operator--()
- {
- if (_node->_left == nullptr)
- {
- // 找祖先里面,孩子是父亲
- Node* cur = _node;
- Node* parent = cur->_parent;
- while (parent && cur == parent->_left)
- {
- cur = cur->_parent;
- parent = parent->_parent;
- }
-
- _node = parent;
- }
- else
- {
- // 左子树的最右节点
- Node* subRight = _node->_left;
- while (subRight->_right)
- {
- subRight = subRight->_right;
- }
-
- _node = subRight;
- }
-
- return *this;
- }
-
- Self operator--(int)
- {
- Self tmp(*this);
-
- --(*this);
-
- return tmp;
- }
比两个对象中的节点即可
- bool operator!=(const Self& s) const
- {
- return _node != s._node;
- }
-
- bool operator==(const Self& s) const
- {
- return _node == s->_node;
- }
至此迭代器的基本实现已完成
由于模板参数的改变和迭代器的实现,使RBTree的实现更加完整,需要对RBTree类进行改变。
首先就是对insert进行改变,有了迭代器的实现,我们应该和库里面的一样,返回的是pair
- pair
bool > Insert(const T& data) - {
- // 1、搜索树的规则插入
- // 2、看是否违反平衡规则,如果违反就需要处理:旋转
- if (_root == nullptr)
- {
- _root = new Node(data);
- _root->_col = BLACK;
- return make_pair(iterator(_root), true);
- }
-
- KeyOfT kot;
-
- Node* parent = nullptr;
- Node* cur = _root;
- 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), true);
- }
- }
-
- cur = new Node(data);
- Node* newnode = cur;
- cur->_col = RED;
- if (kot(parent->_data) < kot(data))
- {
- parent->_right = cur;
- }
- else
- {
- parent->_left = cur;
- }
-
- cur->_parent = parent;
-
- // 存在连续红色节点
- while (parent && parent->_col == RED)
- {
- Node* grandfater = parent->_parent;
- assert(grandfater);
-
- if (grandfater->_left == parent)
- {
- Node* uncle = grandfater->_right;
- // 情况一:
- if (uncle && uncle->_col == RED) // 叔叔存在且为红
- {
- // 变色
- parent->_col = uncle->_col = BLACK;
- grandfater->_col = RED;
-
- // 继续往上处理
- cur = grandfater;
- parent = cur->_parent;
- }
- else // 叔叔不存在 或者 叔叔存在且为黑
- {
- if (cur == parent->_left) // 单旋
- {
- // g
- // p
- // c
- RotateR(grandfater);
- parent->_col = BLACK;
- grandfater->_col = RED;
- }
- else // 双旋
- {
- // g
- // p
- // c
- RotateL(parent);
- RotateR(grandfater);
- cur->_col = BLACK;
- grandfater->_col = RED;
- }
-
- break;
- }
- }
- else //(grandfater->_right == parent)
- {
- Node* uncle = grandfater->_left;
- // 情况一:
- if (uncle && uncle->_col == RED)
- {
- // 变色
- parent->_col = uncle->_col = BLACK;
- grandfater->_col = RED;
-
- // 继续往上处理
- cur = grandfater;
- parent = cur->_parent;
- }
- else
- {
- if (cur == parent->_right)
- {
- // g
- // p
- // c
- RotateL(grandfater);
- parent->_col = BLACK;
- grandfater->_col = RED;
- }
- else // 双旋
- {
- // g
- // p
- // c
- RotateR(parent);
- RotateL(grandfater);
- cur->_col = BLACK;
- grandfater->_col = RED;
- }
-
- break;
- }
- }
- }
-
- _root->_col = BLACK;
-
- return make_pair(iterator(newnode), true);//创建并返回iterator对象
- }
相比原来的insert对返回值做了修改,并用KeyOfT仿函数创建对象来接受其中的K,来进行比较
利用KeyOfT提取T中的K来进行比较找想要找的元素,找到返回迭代器元素位置的迭代器否则返回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();
- }
- enum Colour
- {
- RED,
- BLACK,
- };
-
- template<class T>
- struct RBTreeNode
- {
- RBTreeNode
* _left; - RBTreeNode
* _right; - RBTreeNode
* _parent; - T _data; // 数据
-
- Colour _col;
-
- RBTreeNode(const T& data)
- :_data(data)
- , _left(nullptr)
- , _right(nullptr)
- , _parent(nullptr)
- , _col(RED)
- {}
- };
-
- template<class T, class Ref, class Ptr>
- struct __RBTreeIterator
- {
- typedef RBTreeNode
Node; - typedef __RBTreeIterator
Self; - Node* _node;
-
- __RBTreeIterator(Node* node)
- :_node(node)
- {}
-
- Ref operator*()
- {
- return _node->_data;
- }
-
- Ptr operator->()
- {
- return &_node->_data;
- }
- // 休息17:00
- Self& operator++()
- {
- if (_node->_right == nullptr)
- {
- // 找祖先里面,孩子是父亲左的那个
- Node* cur = _node;
- Node* parent = cur->_parent;
- while (parent && parent->_right == cur)
- {
- cur = cur->_parent;
- parent = parent->_parent;
- }
-
- _node = parent;
- }
- else
- {
- // 右子树的最左节点
- Node* subLeft = _node->_right;
- while (subLeft->_left)
- {
- subLeft = subLeft->_left;
- }
-
- _node = subLeft;
- }
-
- return *this;
- }
-
- Self operator++(int)
- {
- Self tmp(*this);
-
- ++(*this);
-
- return tmp;
- }
-
- Self& operator--()
- {
- if (_node->_left == nullptr)
- {
- // 找祖先里面,孩子是父亲
- Node* cur = _node;
- Node* parent = cur->_parent;
- while (parent && cur == parent->_left)
- {
- cur = cur->_parent;
- parent = parent->_parent;
- }
-
- _node = parent;
- }
- else
- {
- // 左子树的最右节点
- Node* subRight = _node->_left;
- while (subRight->_right)
- {
- subRight = subRight->_right;
- }
-
- _node = subRight;
- }
-
- return *this;
- }
-
- Self operator--(int)
- {
- Self tmp(*this);
-
- --(*this);
-
- return tmp;
- }
-
- bool operator!=(const Self& s) const
- {
- return _node != s._node;
- }
-
- bool operator==(const Self& s) const
- {
- return _node == s->_node;
- }
- };
-
- // T决定红黑树存什么数据
- // set RBTree
- // map RBTree
> - // KeyOfT -> 支持取出T对象中key的仿函数
- template<class K, class T, class KeyOfT>
- class RBTree
- {
- typedef RBTreeNode
Node; - public:
- typedef __RBTreeIterator
iterator; - typedef __RBTreeIterator
const T&, const T*> const_iterator; -
- // 构造 拷贝构造 赋值 和析构 跟搜索树实现方式是一样的
-
- iterator Begin()
- {
- Node* subLeft = _root;
- while (subLeft && subLeft->_left)
- {
- subLeft = subLeft->_left;
- }
-
- return iterator(subLeft);
- }
-
- iterator End()
- {
- return iterator(nullptr);
- }
-
- const_iterator Begin() const
- {
- Node* subLeft = _root;
- while (subLeft && subLeft->_left)
- {
- subLeft = subLeft->_left;
- }
-
- return const_iterator(subLeft);
- }
-
- const_iterator End() const
- {
- return const_iterator(nullptr);
- }
-
- pair
bool > Insert(const T& data) - {
- // 1、搜索树的规则插入
- // 2、看是否违反平衡规则,如果违反就需要处理:旋转
- if (_root == nullptr)
- {
- _root = new Node(data);
- _root->_col = BLACK;
- return make_pair(iterator(_root), true);
- }
-
- KeyOfT kot;
-
- Node* parent = nullptr;
- Node* cur = _root;
- 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), true);
- }
- }
-
- cur = new Node(data);
- Node* newnode = cur;
- cur->_col = RED;
- if (kot(parent->_data) < kot(data))
- {
- parent->_right = cur;
- }
- else
- {
- parent->_left = cur;
- }
-
- cur->_parent = parent;
-
- // 存在连续红色节点
- while (parent && parent->_col == RED)
- {
- Node* grandfater = parent->_parent;
- assert(grandfater);
-
- if (grandfater->_left == parent)
- {
- Node* uncle = grandfater->_right;
- // 情况一:
- if (uncle && uncle->_col == RED) // 叔叔存在且为红
- {
- // 变色
- parent->_col = uncle->_col = BLACK;
- grandfater->_col = RED;
-
- // 继续往上处理
- cur = grandfater;
- parent = cur->_parent;
- }
- else // 叔叔不存在 或者 叔叔存在且为黑
- {
- if (cur == parent->_left) // 单旋
- {
- // g
- // p
- // c
- RotateR(grandfater);
- parent->_col = BLACK;
- grandfater->_col = RED;
- }
- else // 双旋
- {
- // g
- // p
- // c
- RotateL(parent);
- RotateR(grandfater);
- cur->_col = BLACK;
- grandfater->_col = RED;
- }
-
- break;
- }
- }
- else //(grandfater->_right == parent)
- {
- Node* uncle = grandfater->_left;
- // 情况一:
- if (uncle && uncle->_col == RED)
- {
- // 变色
- parent->_col = uncle->_col = BLACK;
- grandfater->_col = RED;
-
- // 继续往上处理
- cur = grandfater;
- parent = cur->_parent;
- }
- else
- {
- if (cur == parent->_right)
- {
- // g
- // p
- // c
- RotateL(grandfater);
- parent->_col = BLACK;
- grandfater->_col = RED;
- }
- else // 双旋
- {
- // g
- // p
- // c
- RotateR(parent);
- RotateL(grandfater);
- cur->_col = BLACK;
- grandfater->_col = RED;
- }
-
- break;
- }
- }
- }
-
- _root->_col = BLACK;
-
- return make_pair(iterator(newnode), true);
- }
-
- void RotateL(Node* parent)
- {
- Node* subR = parent->_right;
- Node* subRL = subR->_left;
-
- parent->_right = subRL;
- if (subRL)
- subRL->_parent = parent;
-
- Node* ppNode = parent->_parent;
-
- subR->_left = parent;
- parent->_parent = subR;
-
- if (parent == _root)
- {
- _root = subR;
- _root->_parent = nullptr;
- }
- else
- {
- if (parent == ppNode->_left)
- {
- ppNode->_left = subR;
- }
- else
- {
- ppNode->_right = subR;
- }
-
- subR->_parent = ppNode;
- }
- }
-
- void RotateR(Node* parent)
- {
- Node* subL = parent->_left;
- Node* subLR = subL->_right;
-
- parent->_left = subLR;
- if (subLR)
- subLR->_parent = parent;
-
- Node* ppNode = parent->_parent;
-
- subL->_right = parent;
- parent->_parent = subL;
-
- if (parent == _root)
- {
- _root = subL;
- _root->_parent = nullptr;
- }
- else
- {
- if (ppNode->_left == parent)
- {
- ppNode->_left = subL;
- }
- else
- {
- ppNode->_right = subL;
- }
- subL->_parent = ppNode;
- }
- }
-
- 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();
- }
-
- private:
- Node* _root = nullptr;
- };
set的底层结构就是红黑树,因此在set中直接封装一棵红黑树,然后将其接口包装下即可
由于在RBTree中传了KeyOfT来获取K,因此我们在set中需要实现一个仿函数来获取set的K
- template<class K>
- class set
- {
- //给红黑树获取K
- struct SetkeyOfT
- {
- const K& operator()(const K& key)
- {
- return key;
- }
- };
其他都是包装RBTree的接口即可
注意:
由于set的Key是不能改变的,所以set的iterator应该用const_iterator包装。
但是会进一步导致insert函数在返回时,由于RBTree的iterator里的参数没有被const修饰是普通迭代器,但是set的iterator是const_iterator,就会出现iterator向const_iterator的转化,这是两个封装后毫无关系的类型,无法直接转化,因此我们需要先提取出来返回值稍作修改后重新封装,因此insert应该做出如下改造:
- pair
bool > insert(const K& key) - {
- //pair
::iterator, bool> ret = _t.Insert(key); - auto ret = _t.Insert(key);
- return pair
bool>(iterator(ret.first._node), ret.second); - }
注意:
这里和list实现迭代器一样,当我们typedef迭代器时,会出现内嵌类型的问题,需要使用到typename关键字
set具体封装的实现代码:
- #include "RBTree.h"
-
- namespace mystl
- {
- template<class K>
- class set
- {
- //给红黑树获取K
- struct SetkeyOfT
- {
- const K& operator()(const K& key)
- {
- return key;
- }
- };
- public:
-
- typedef typename RBTree
::const_iterator iterator; - typedef typename RBTree
::const_iterator const_iterator; -
- //set不能修改,只提供const版本
- iterator begin() const
- {
- return _t.Begin();
- }
-
- iterator end() const
- {
- return _t.End();
- }
-
- pair
bool > insert(const K& key) - {
- //pair
::iterator, bool> ret = _t.Insert(key); - auto ret = _t.Insert(key);
- return pair
bool>(iterator(ret.first._node), ret.second); - }
-
- iterator find(const K& key)
- {
- return _t.find(key);
- }
-
- private:
- RBTree
_t; - };
- }
这里需要的注意事项和set,唯一不同的是这里insert没有set的问题,因为map的iterator就是RBTree的普通迭代器封装的,因map的V是可以更改的,map和set的K是不能更改的,所以map的普通迭代器应该封装成普通的迭代器供V改变,因此,insert可以直接返回封装的insert的返回值。
map实现了operator[],这里也可以实现,直接封装RBTree的insert,返回值是RBTree返回值的V的引用供修改即可
实现代码如下:
- V& operator[](const K& key)
- {
- pair
bool> ret = insert(make_pair(key, V())); -
- return ret.first->second;
- }
其他直接封装RBTree的接口即可,j具体实现代码如下:
- #include "RBTree.h"
-
- namespace mystl
- {
- template<class K, class V>
- class map
- {
- //给红黑树获取K
- struct MapkeyOfT
- {
- const K& operator()(const pair
& kv) - {
- return kv.first;
- }
- };
-
- public:
-
- typedef typename RBTree
, MapkeyOfT>::iterator iterator; - typedef typename RBTree
, MapkeyOfT>::const_iterator const_iterator; -
- //map可以修改都提供
- iterator begin()
- {
- return _t.Begin();
- }
-
- iterator end()
- {
- return _t.End();
- }
-
- pair
bool > insert(const pair& kv) - {
- return _t.Insert(kv);
- }
-
- iterator find(const K& key)
- {
- return _t.find(key);
- }
-
- V& operator[](const K& key)
- {
- pair
bool> ret = insert(make_pair(key, V())); -
- return ret.first->second;
- }
-
- private:
- RBTree
, MapkeyOfT> _t; - };
- }