【STL源码剖析】总结笔记(8):红黑树(RB-tree)探究
这篇的内容在红黑树的基础上就显得简单很多了。set和map需要了解其结构,在实际使用STL过程中最好可以做到轻松使用。
因为是红黑树作为底层,所以要注意元素是会自动排序的。
set的底层是依靠红黑树来支撑的,所以会根据元素的key自动排序。对于set来说,key就是value,而且set不允许两个元素有相同的key。
同理,我们也不可以修改set的元素值,这一点可以从后面set的iterator中看出来。
set的结构如下:
template <class Key,class Compare=less<Key>,class Alloc=alloc> class set{ public: typedef Key key_type; typedef Key value_type; typedef Compare key_compare; typedef Compare Value_compare; private: typedef rb_tree<key_type,value_type,identity<value_type>.key_compare,Alloc>rep_type; rep_type t; }
重点关注这样几个点:
identity的定义如下:
template<class T> struct identity:public unary_function<T,T>{ const T& operator()(const T& x)const{return x;} }
也就是传入自己,返回自己。
再看一下set的iterator
typedef typename rep_type::const_iterator iterator;
是rb_tree的const_iterator,也说明了不可随意改动元素值。
这样看其实set很像我们前面提到的container adapter(容器适配器),因为它的功能都是依靠红黑树实现的。
multiset允许key重复,这也是与set的区别。
而它们的底层都是依靠红黑树实现的,那是如何区分的呢?
其实就是区别在于红黑树的insert函数的使用。
set使用的是红黑树的insert_unique(),保证插入元素不重复,而multiset使用的是insert_equal(),在插入时元素可以相同。
insert_unique()在插入相同元素时不会报错,只是不能插入成功。
map的底层也是依靠红黑树来支撑的,所以会根据元素的key自动排序。map比较特殊的一点是所有的元素都是成对的(pair),pair包括key和value,map不允许两个元素拥有相同的key,而且iterator也不可修改key,但是可以修改value。
map的结构如下:
template <class Key,class T,class Compare=less<Key>,class Alloc=alloc> class map{ public: typedef key key_type; typedef T data_type; typedef T mapped_type; typedef pair<const Key,T> value_type; typedef Compare key_compare; ... private: typedef rb_tree<key_type,value_type,select1st<value_type>,key_compare,Alloc>rep_type; rep_type t; }
从上往下看需要注意:
再来看一下iterator
typedef typename rep_type::iterator iterator;
这里的iterator并不是类似set中的const_iterator,因为允许通过iterator修改value,但是key不可修改。
所以在上面的定义中Key是const类型的。
还有一个map独有的操作符[]
T& operator[](const key_type& k){ return (*((insert(value_type(k,T()))),first)).second; }
简单解释一下这个操作。比如有一个map是a,那么a[i]就可以传入key用来找对应的value。如果不存在,那么会插入默认值。
multimap与map的区别也和上面一样,就是允许键值重复。
map使用的是红黑树的insert_unique(),保证插入元素不重复,而multimap使用的是insert_equal(),在插入时元素可以相同。