Map和Set的封装(RBTree实现,包含迭代器)
用RBTree封装Map和Set主要需要解决以下几个问题
- Set存储的是key,Map存储的是key/value,如何用RBTree兼容两者
- Map和Set迭代器的初步实现
- 如何解决Set中key不能被修改,Map中key不能被修改,value能被修改的问题
- Insert插入返回值问题以及Map[]的重载实现
一、问题1
Set存储的是key,Map存储的是key/value,如何用RBTree兼容两者实现封装呢?
我们可以查看库中的源码,如下图:
我们不难看出在库中红黑树的实现有五个个模板参数,我们重点看前三个
分别是 Key ,Value , KeyOfValue
而其中第二个Value就是决定node中存什么结构的
明白这一点就引出了下一个问题
如果是key结构,红黑树在插入的时候可以直接比较,但如果是key/value结构,本质上是一个键值对pair<first,second>,键值对能直接比较吗,我们可以查阅了文档,
如图:
此处说明对于pair的比较,first和second只要有一个小,pair就小,但这和我们想要的规则不同,我们要做的是搜索二叉树的插入,比较的仅仅只有key值,并且key值相同时无法插入。
所以接下来需要解决比较这个问题,而如何解决的答案就在第三个模板参数 KeyOfValue 上,KeyOfValue是一个内部类,是map和set内部实现的一个类,该类中实现了一个仿函数operator(),而该仿函数返回的值就是需要比较的key,这么讲可能有点抽象,上代码图帮助理解
这是一个泛型的思想,无论是map还是set,都能一套实现,set中就是走个过场直接返回key,而map中返回pair中的first
二、问题2
map和set的迭代器本质上是复用红黑树中的迭代器,所以我们先实现红黑树的迭代器
首先我们需要明确的是,红黑树是一个双向迭代器,支持+ +,- -操作,并且因为红黑树是一颗搜索二叉树,既然设计迭代器,迭代器就需要有价值,所以迭代器应该走的是红黑树的中序遍历
迭代器的begin指向的应该是树的最左节点,end指向的是空
主要实现迭代器 =,++,- -,*,->,==,!= 的功能
此处应该没什么难点,树的迭代器的本质就是封装了树的节点
值得一提的是++与- -运算符的实现,由于我们走的是中序遍历,如何找到下一个节点或者如何找到上一个节点,需要仔细想想,代码处提供了思路,这里不多赘述
template <class T>
struct _treeiterator
{
typedef TreeNode<T> Node;
typedef _treeiterator<T> Self;
Node* _node;
_treeiterator(Node* node)
:_node(node)
{}
_treeiterator(const iterator& x)
:_node(x._node)
{}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
//有右孩子,找右孩子的最左节点
//没右孩子,找孩子是父亲的左节点的祖先
Self& operator++()
{
if (_node->_right)
{
_node = _node->_right;
while (_node->_left)
{
_node = _node->_left;
}
}
else
{
Node* parent = _node->_parent;
while (parent && parent->_right == _node)
{
_node = parent;
parent = _node->_parent;
}
_node = parent;
}
return *this;
}
//有左孩子,找左孩子的最右节点
//没左孩子,找孩子是父亲的右节点的祖先
Self& operator--()
{
if (_node->_left)
{
_node = _node->_left;
while (_node->_right)
{
_node = _node->_right;
}
}
else
{
Node* parent = _node->_parent;
while (parent && parent->_left == _node)
{
_node = parent;
parent = _node->_parent;
}
_node = parent;
}
return *this;
}
bool operator!=(const Self& it)
{
return _node != it._node;
}
bool operator==(const Self& it)
{
return _node == it._node;
}
};
三、问题3
在初步实现了迭代器以后,在map和set中复用上,就能够遍历树了
但还存在一定的问题,*it时无论是set的key还是map的first都能被修改,如果树中的key能够被允许修改,那么红黑树将毫无意义,因为红黑树是一颗搜索二叉树,正是因为它的结构,使得有排序和查找的价值,一但结构被破坏,就丧失了其价值
所以我们还需要进一步解决key不能被修改的问题
我们参考库中解决Set中key不能被修改,Map中key不能被修改,value能被修改的问题
我们可以看出库中set的iterator和const_iterator都是红黑树的const_iterator复用而来
map中的iterator是红黑树的iterator复用而来,const_iterator是红黑树的const_iterator复用而来,而map解决key不能被修改,value能被修改的原理也很简单,就是在实例化的时候,声明第二个模板参数——在map中也就是pair,pair的first是const类型
所以,我们还需要实现红黑树的const_iterator,map中的iterator和const_iterator都用其复用
更值得注意的是const_iterator的实现不仅仅是在iterator前面加一个const,因为iterator是一个封装的类,iterator和const_iterator是两个不同的类,所以要实现红黑树的const_iterator的话就需要再用到模板,是什么迭代器取决于实例化的时候是什么类型的参数
template <class T, class Ref, class Ptr>
struct _treeiterator
{
typedef TreeNode<T> Node;
typedef _treeiterator<T, T&, T*> iterator;
typedef _treeiterator<T, Ref, Ptr> Self;
Node* _node;
_treeiterator(Node* node)
:_node(node)
{}
_treeiterator(const iterator& x)
:_node(x._node)
{}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
//有右孩子,找右孩子的最左节点
//没右孩子,找孩子是父亲的左节点的祖先
Self& operator++()
{
if (_node->_right)
{
_node = _node->_right;
while (_node->_left)
{
_node = _node->_left;
}
}
else
{
Node* parent = _node->_parent;
while (parent && parent->_right == _node)
{
_node = parent;
parent = _node->_parent;
}
_node = parent;
}
return *this;
}
//有左孩子,找左孩子的最右节点
//没左孩子,找孩子是父亲的右节点的祖先
Self& operator--()
{
if (_node->_left)
{
_node = _node->_left;
while (_node->_right)
{
_node = _node->_right;
}
}
else
{
Node* parent = _node->_parent;
while (parent && parent->_left == _node)
{
_node = parent;
parent = _node->_parent;
}
_node = parent;
}
return *this;
}
bool operator!=(const Self& it)
{
return _node != it._node;
}
bool operator==(const Self& it)
{
return _node == it._node;
}
};
四、问题4
解决完以上三个问题以后,迭代器也实现完成,接下来我们就可以来看看库中的库中Insert插入是怎么玩的了,其实大部分实现是相同的,具体看之前的红黑树相关文章,不同的是库中Insert的返回值
无论是set还是map的insert的返回值都是一个键值对,first是一个迭代器,second是一个bool类型,这意味着红黑树中的insert也是一样,因为set和map在库中是红黑树封装的,所以如果树中存在该key值,返回key所在节点的迭代器,如果不存在该key值,那么插入key,也返回该新增节点的迭代器,bool类型则是判断是否成功插入,如果存在则是插入失败,不存在则说明是新增,则插入成功,这说明insert函数还具有查找功能
基于此性质,引出了map的计数功能,可以通过insert返回的迭代器查看是否有key值,如果不存在则插入,将value值赋值为1,如果key已经存在,则通过insert返回的迭代器将value++,以此实现计数功能,所以map实现了operator[],用来计数
V& operator[](const K& key)
{
pair<iterator, bool> ret = insert(make_pair(key, V()));
return ret.first->second;
}
五、封装代码
map.h
#include "RBTree.h"
namespace Tlzns
{
template<class K, class V>
class map
{
public:
struct KeyOfT
{
const K& operator()(const pair<K,V>& data)
{
return data.first;
}
};
typedef typename RBTree<K, pair<const K, V>, KeyOfT>::iterator iterator;
typedef typename RBTree<K, pair<const K, V>, KeyOfT>::const_iterator const_iterator;
pair<iterator, bool> insert(const pair<K, V>& data)
{
return _t.Insert(data);
}
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;
return insert(make_pair(key, V())).first->second;
}
private:
RBTree<K, pair<const K, V>, KeyOfT> _t;
};
}
set.h
#include "RBTree.h"
namespace Tlzns
{
template<class K>
class set
{
public:
struct KeyOfT
{
const K& operator()(const K& data)
{
return data;
}
};
typedef typename RBTree<K, K, KeyOfT>::const_iterator iterator;
typedef typename RBTree<K, K, KeyOfT>::const_iterator const_iterator;
pair<iterator, bool> insert(const K& data)
{
return _t.Insert(data);
}
iterator begin()const
{
return _t.begin();
}
iterator end()const
{
return _t.end();
}
private:
RBTree<K, K, KeyOfT> _t;
};
}
RBTree.h
#include <iostream>
using namespace std;
enum Color
{
Red,
Black
};
template <class T>
struct TreeNode
{
TreeNode(const T& data)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
, _col(Red)
{}
TreeNode* _left;
TreeNode* _right;
TreeNode* _parent;
T _data;
Color _col;
};
template <class T, class Ref, class Ptr>
struct _treeiterator
{
typedef TreeNode<T> Node;
typedef _treeiterator<T, T&, T*> iterator;
typedef _treeiterator<T, Ref, Ptr> Self;
Node* _node;
_treeiterator(Node* node)
:_node(node)
{}
_treeiterator(const iterator& x)
:_node(x._node)
{}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
//有右孩子,找右孩子的最左节点
//没右孩子,找孩子是父亲的左节点的祖先
Self& operator++()
{
if (_node->_right)
{
_node = _node->_right;
while (_node->_left)
{
_node = _node->_left;
}
}
else
{
Node* parent = _node->_parent;
while (parent && parent->_right == _node)
{
_node = parent;
parent = _node->_parent;
}
_node = parent;
}
return *this;
}
//有左孩子,找左孩子的最右节点
//没左孩子,找孩子是父亲的右节点的祖先
Self& operator--()
{
if (_node->_left)
{
_node = _node->_left;
while (_node->_right)
{
_node = _node->_right;
}
}
else
{
Node* parent = _node->_parent;
while (parent && parent->_left == _node)
{
_node = parent;
parent = _node->_parent;
}
_node = parent;
}
return *this;
}
bool operator!=(const Self& it)
{
return _node != it._node;
}
bool operator==(const Self& it)
{
return _node == it._node;
}
};
template <class K, class T, class KeyOfT>
class RBTree
{
typedef TreeNode<T> Node;
public:
//typedef _treeiterator<T> iterator;
typedef _treeiterator<T, T&, T*> iterator;
typedef _treeiterator<T, const T&, const T*> const_iterator;
iterator begin()
{
if (_root == nullptr)
{
return nullptr;
}
Node* cur = _root;
while (cur->_left)
{
cur = cur->_left;
}
return cur;
}
iterator end()
{
return nullptr;
}
const_iterator begin()const
{
if (_root == nullptr)
{
return nullptr;
}
Node* cur = _root;
while (cur->_left)
{
cur = cur->_left;
}
return cur;
}
const_iterator end()const
{
return nullptr;
}
//pair<iterator, bool> Insert(const T& data)
pair<Node*, bool> Insert(const T& data)
{
if (_root == nullptr)
{
_root = new Node(data);
_root->_col = Black;
return make_pair(_root, true);
}
KeyOfT kof;
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (kof(cur->_data) > kof(data))
{
parent = cur;
cur = cur->_left;
}
else if (kof(cur->_data) < kof(data))
{
parent = cur;
cur = cur->_right;
}
else
{
return make_pair(cur, false);
}
}
Node* newnode = new Node(data);
if (kof(parent->_data) > kof(data))
{
cur = newnode;
parent->_left = cur;
cur->_parent = parent;
}
else
{
cur = newnode;
parent->_right = cur;
cur->_parent = parent;
}
while (parent && parent->_col == Red)
{
if (parent->_col == Black)
{
break;
}
//parent是红色,需要先找祖父,再寻找uncle
Node* grandparent = parent->_parent;
Node* uncle = nullptr;
//parent在左 uncle在右
if (grandparent->_left == parent)
{
uncle = grandparent->_right;
//uncle存在且为红色
if (uncle && uncle->_col == Red)
{
parent->_col = Black;
uncle->_col = Black;
grandparent->_col = Red;
//继续向上更新
cur = grandparent;
parent = cur->_parent;
}
//uncle存在且为黑色或者uncle不存在
else
{
//cur在左,右单旋
if (cur == parent->_left)
{
RotateR(grandparent);
parent->_col = Black;
grandparent->_col = Red;
break;
}
//cur在右,双旋
else
{
RotateL(parent);
RotateR(grandparent);
cur->_col = Black;
grandparent->_col = Red;
break;
}
}
}
//parent在右 uncle在左
else
{
uncle = grandparent->_left;
//uncle存在且为红色
if (uncle && uncle->_col == Red)
{
parent->_col = uncle->_col = Black;
grandparent->_col = Red;
cur = grandparent;
parent = cur->_parent;
}
//uncle存在且为黑色或uncle不存在
else
{
//cur在右,左单旋
if (cur == parent->_right)
{
RotateL(grandparent);
parent->_col = Black;
grandparent->_col = Red;
break;
}
//cur在左,双旋
else
{
RotateR(parent);
RotateL(grandparent);
cur->_col = Black;
grandparent->_col = Red;
break;
}
}
}
}
_root->_col = Black;
return make_pair(newnode, true);
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
subR->_left = parent;
Node* parentparent = parent->_parent;
if (subRL)
subRL->_parent = parent;
parent->_parent = subR;
if (parent == _root)
{
subR->_parent = nullptr;
_root = subR;
}
else
{
subR->_parent = parentparent;
if (parentparent->_left == parent)
{
parentparent->_left = subR;
}
else
{
parentparent->_right = subR;
}
}
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
subL->_right = parent;
Node* parentparent = parent->_parent;
if (subLR)
{
subLR->_parent = parent;
}
parent->_parent = subL;
if (parent == _root)
{
subL->_parent = nullptr;
_root = subL;
}
else
{
subL->_parent = parentparent;
if (parentparent->_left == parent)
{
parentparent->_left = subL;
}
else
{
parentparent->_right = subL;
}
}
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
bool Isbalance()
{
if (_root == nullptr)
{
return true;
}
if (_root->_col == Red)
{
return false;
}
size_t reference = 0;
Node* cur = _root;
while (cur)
{
if (cur->_col == Black)
{
reference++;
}
cur = cur->_left;
}
return _Isbalance(_root, reference, 0);
}
private:
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
KeyOfT kof;
_InOrder(root->_left);
cout << kof(root->_data) << " ";
_InOrder(root->_right);
}
bool _Isbalance(Node* root, size_t reference, size_t bnum)
{
if (root == nullptr)
{
if (bnum != reference)
{
cout << "每条路径黑色节点个数不同" << endl;
return false;
}
return true;
}
if (root->_col == Red)
{
if (root->_parent->_col != Black)
{
cout << "出现连续的红色节点" << endl;
return false;
}
}
else
{
bnum++;
}
return _Isbalance(root->_left, reference, bnum) && _Isbalance(root->_right, reference, bnum);
}
Node* _root = nullptr;
};
此篇文章主要讲map和set用RBTree封装的思路,学习库中的玩法