点击蓝字关注我哦
以下是本期干货视频 视频后还附有文字版本哦 ▼ 《STL map的底层实现原理之代码探秘》 ▼ ps:请在WiFi环境下打开,如果有钱任性请随意 了解了红黑树,也知道了如何做出平衡调整,这就意味着我们具备了探究红黑树代码的资本,本小节我们从调试的角度,带着大家探究一下红黑树的重要接口,以及探究map结构是如何在红黑树的基础上来进行实现的。 红黑树的重要接口
template<class _K, class _Ty, class _Kfn, class _Pr, class _A>
class _Tree
{
protected:
enum _Redbl {_Red, _Black}; //颜色定义
//红黑树节点定义
struct _Node
{
_Nodeptr _Left, _Parent, _Right;
_Ty _Value;
_Redbl _Color;
};
public:
//迭代器类型
class iterator;
class const_iterator;
iterator begin();
iterator end();
public:
//可以根据标记值决定是否允许插入重复值,这个对实现map和multimap就可以统一为一个函数实现
_Pairib insert(const value_type& _V);
size_type erase(const _K& _X);
//左单旋转
void _Lrotate(_Nodeptr _X);
//右单旋转
void _Rrotate(_Nodeptr _X);
private:
_A allocator; //空间配置器
_Pr key_compare; //关键字比较谓词
_Nodeptr _Head; //红黑树头结点
bool _Multi; //是否允许插入重复值的标记
size_type _Size; //节点个数
};
[注]: 1. 在红黑树中没有双旋转函数的实现,当要进行双旋转时,是通过两个单旋转拼凑而成的。
2.红黑树可以根据标记值决定是否允许插入重复值,从而可以达到map和multimap的统一实现。
map的实现
底层有了红黑树,map的实现可谓轻而易举,因为map的所有操作几乎都是转为调用红黑树的接口,其中不允许插入重复值就是map容器,允许插入重复值就是multimap容器,以下为map的类接口。
template<class _K, class _Ty, class _Pr = less<_k>,class _A = allocator<_ty> >
class map
{
public:
//......
//红黑树类型定义
typedef _Tree<_k value_type _kfn _pr _a> _Imp;
//......
protected:
_Imp _Tr; //实例化红黑树对象成员
public:
explicit map(const _Pr& _Pred = _Pr(), const _A& _Al = _A())
: _Tr(_Pred, false, _Al) {}
iterator begin()
{return (_Tr.begin()); }
iterator end()
{return (_Tr.end()); }
size_type size() const
{return (_Tr.size()); }
size_type max_size() const
{return (_Tr.max_size()); }
bool empty() const
{return (_Tr.empty()); }
_Tref operator[](const key_type& _Kv)
{iterator _P = insert(value_type(_Kv, _Ty())).first;
return ((*_P).second); }
_Pairib insert(const value_type& _X)
{_Imp::_Pairib _Ans = _Tr.insert(_X);
return (_Pairib(_Ans.first, _Ans.second)); }
iterator insert(iterator _P, const value_type& _X)
{return (_Tr.insert((_Imp::iterator&)_P, _X)); }
void insert(_It _F, _It _L)
{for (; _F != _L; ++_F)
_Tr.insert(*_F); }
iterator erase(iterator _P)
{return (_Tr.erase((_Imp::iterator&)_P)); }
iterator erase(iterator _F, iterator _L)
{return (_Tr.erase((_Imp::iterator&)_F,
(_Imp::iterator&)_L)); }
size_type erase(const _K& _Kv)
{return (_Tr.erase(_Kv)); }
void clear()
{_Tr.clear(); }
//.........
};
以上摘取了部分主要接口,可以看到,map底层就一个红黑树对象成员,从各种实现可以看到,map的操作几乎都是转调用红黑树接口而已,所以,要理解map的实现,其核心就必须理解红黑树的实现。
小结
作者:鲍松山
审稿:王海斌
编辑:小丸子
点亮"在看",点亮"offer"
原创不易,点个赞吧~