一、前言
进行set和map封装之前我们先来看一下标准库中的set和map是如何进行实现的。


看完这两段源码我们应该已经清楚了set和map的实现方式,它们两个的成员变量使用的都是rep_type这种类型的成员,rep_type这种类型是typedef得到的,它的原型是rb_tree<key_type, value_type, select1st<value_type>, key_compare, Alloc>,也就是说它的原型是一个类模板。也就是说它们两个的底层使用的都是红黑树来实现的。下面我们来看一下红黑树的底层实现方式



实现set和map主要就是通过传入rb_tree这个模板的几个模板参数实现的。所以我们的主要任务就是搞清楚这几个模板参数究竟是什么。
set:

map:

set:

map:

我们可以发现set得key_type和value_type都是key类型的,在实例化rb_tree模板时传了两个key,在看一下map,它的第一个参数依然时key第二个参数时pair类型,这意味着什么呢,其实很容易理解,为了复用已经实现好的这棵红黑树,只能这样实现。
那么为什么要传两个key呢?其实这个问题也是很简单的,因为后续实现find,erase都是依赖于key的,虽然set只传一个key就可以了,但是为了兼容map就必须要传两个key。
下面我们再来看一下第三个参数keyofvalue。keyofvalue实际上是为了解决pair中key比较的问题,由于要兼容map说一set依要实现一个。
二、搭出整体的框架
namespace Code_Journey
{
struct SetKeyOfT
{
template<class Key>
const Key operator()(const Key& key)
{
return key;
}
};
template<class K>
class set
{
public:
bool insert(const K& key)
{
return t.insert(key);
}
private:
typedef RBTree<K, K, SetKeyOfT> rb_tree;
rb_tree t;
};
}
namespace Code_Journey
{
struct MapKeyOfT
{
template<class K, class V>
const K operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
template<class K, class V>
class map
{
public:
bool insert(const pair<K, V>& kv)
{
return t.insert(kv);
}
private:
typedef RBTree<K, pair<K, V>, MapKeyOfT> rb_tree;
rb_tree t;
};
}
三、实现迭代器
map和set是双向迭代器,又要实现普通迭代器和const迭代器。下面我们来分别进行实现。
3.1、普通迭代器的实现
3.1.1、operator++和operator--的实现
这里我们之讲解operator++的实现思路,operator--的实现思路和++非常类似,只是需要反过来想一下就可以。
实现这两个函数一定不要太去关注全局,只需要关注当下的每一步即可。
++的实现思路就是如果说当前结点的右子树如果为空的话,就持续向上遍历,直到当前结点为其父结点的左子树,就将_node赋值为parent。
如果右子树不为空的话,就找右子树的最左节点作为下一节点赋值给_node。
细节分析:第一点,如果右子树为空,就说明按照左子树,根结点,右子树的遍历规则已经将这一棵子树遍历完成了,接下来就是遍历下一个子树,只有当当前结点为其父节点的左子树的时候才证明下一结点就是我们要遍历的结点。如果一直到了空没有找到这个结点,那么空就是最后一个结点,正好满足end()为空的情况。
第二点,如果右结点不为空,那就遍历右子树,直找到右子树的最小结点作为下一结点。
Sef& operator++()
{
Node* cur = _node;
if (cur && cur->_right)
{
// 找右子树的最小结点
Node* minLeft = cur->_right;
while (minLeft->_left)
{
minLeft = minLeft->_left;
}
_node = minLeft;
}
else
{
if (cur)
{
Node* parent = cur->_parent;
while (parent && cur != parent->_left)
{
cur = parent;
parent = cur->_parent;
}
_node = parent;
}
}
return *this;
}
Sef& operator--()
{
Node* cur = _node;
if (_root && cur == nullptr)
{
Node* maxRight = _root;
while (maxRight->_right)
{
maxRight = maxRight->_right;
}
_node = maxRight;
}
else if (cur && cur->_left)
{
// 找左子树的最大结点
Node* maxRight = cur->_left;
while (maxRight->_right)
{
maxRight = maxRight->_right;
}
_node = maxRight;
}
else
{
if (cur)
{
Node* parent = cur->_parent;
while (parent && cur != parent->_right)
{
cur = parent;
parent = cur->_parent;
}
_node = parent;
}
}
return *this;
}
3.1.2、普通迭代器的封装
对于迭代器的封装我们一步一步的进行,下面先实现出普通的迭代器,进而实现const迭代器。
template<class T>
struct rb_iterator
{
typedef rb_iterator iterator;
typedef rb_iterator Sef;
typedef RBTreeNode<T> Node;
Node* _node;
Node* _root;
rb_iterator(Node* node, Node* root)
:_node(node)
,_root(root)
{}
T& operator*()
{
return _node->_kv;
}
T* operator->()
{
return &_node->_kv;
}
bool operator==(iterator it)
{
return _node == it._node;
}
bool operator!=(iterator it)
{
return _node != it._node;
}
Sef& operator++()
{
Node* cur = _node;
if (cur && cur->_right)
{
// 找右子树的最小结点
Node* minLeft = cur->_right;
while (minLeft->_left)
{
minLeft = minLeft->_left;
}
_node = minLeft;
}
else
{
if (cur)
{
Node* parent = cur->_parent;
while (parent && cur != parent->_left)
{
cur = parent;
parent = cur->_parent;
}
_node = parent;
}
}
return *this;
}
Sef& operator--()
{
Node* cur = _node;
if (_root && cur == nullptr)
{
Node* maxRight = _root;
while (maxRight->_right)
{
maxRight = maxRight->_right;
}
_node = maxRight;
}
else if (cur && cur->_left)
{
// 找左子树的最大结点
Node* maxRight = cur->_left;
while (maxRight->_right)
{
maxRight = maxRight->_right;
}
_node = maxRight;
}
else
{
if (cur)
{
Node* parent = cur->_parent;
while (parent && cur != parent->_right)
{
cur = parent;
parent = cur->_parent;
}
_node = parent;
}
}
return *this;
}
};
3.2、const迭代器的实现
template<class T, class Ref, class Ptr>
struct rb_iterator
{
typedef rb_iterator Sef;
typedef RBTreeNode<T> Node;
Node* _node;
Node* _root;
rb_iterator(Node* node, Node* root)
:_node(node)
,_root(root)
{}
Ref operator*()
{
return _node->_kv;
}
Ptr operator->()
{
return &_node->_kv;
}
bool operator==(const Sef& it)
{
return _node == it._node;
}
bool operator!=(const Sef& it)
{
return _node != it._node;
}
Sef& operator++()
{
Node* cur = _node;
if (cur && cur->_right)
{
// 找右子树的最小结点
Node* minLeft = cur->_right;
while (minLeft->_left)
{
minLeft = minLeft->_left;
}
_node = minLeft;
}
else
{
if (cur)
{
Node* parent = cur->_parent;
while (parent && cur != parent->_left)
{
cur = parent;
parent = cur->_parent;
}
_node = parent;
}
}
return *this;
}
Sef& operator--()
{
Node* cur = _node;
if (_root && cur == nullptr)
{
Node* maxRight = _root;
while (maxRight->_right)
{
maxRight = maxRight->_right;
}
_node = maxRight;
}
else if (cur && cur->_left)
{
// 找左子树的最大结点
Node* maxRight = cur->_left;
while (maxRight->_right)
{
maxRight = maxRight->_right;
}
_node = maxRight;
}
else
{
if (cur)
{
Node* parent = cur->_parent;
while (parent && cur != parent->_right)
{
cur = parent;
parent = cur->_parent;
}
_node = parent;
}
}
return *this;
}
};
四、operator[]的实现
map[]的实现主要是依靠insert这个接口进行实现的,所以我们要先修改我们的insert这个口,就是它的返回值改成一个pair<iterator,bool>,如果没有这个元素他就会插入并且返回它所在位置的迭代器更新第二个bool值为true,如果有的话他就会返回它所在位置的迭代器更新bool值为false。所以说对于[]的实现insert主要充当一个查找的功能。
V& operator[](const K& key)
{
pair<iterator, bool> kv = insert({ key, V() });
iterator it = kv.first;
return it->second;
}

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



