续篇~~上一篇简要的列了一下红黑树的底层设计
关联式容器分为set(集合)、map(映射表),以及两个衍生体multiset(多键集合)、multimap(多键映射表),它们的底层机制都是RB_tree(红黑树),RB_tree也是一个独立容器,只不过不对外界开放。
1、set
set的特性,所有元素会根据键值(key)自动被排序,set和map不一样,set的键值(key)就是实值(value),实值(value)就是键值(key),而且set中的键值不允许重复。
所以想通过迭代器去改变set的value值也是不被允许的,因为它的实值就是键值,关系到整个集合的排序,所以它也将迭代器设计成constant iterator.
另一个比较重要的特性就是set与list有某些相同的性质,它的迭代器在插入或者删除之后也不会失效,已经被删除的那个迭代器例外。
// 比较器默认采用less,内部按照升序排列
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class set
{
public:
// 在set中key就是value, value同时也是key
typedef Key key_type;
typedef Key value_type;
// 使用的同一个比较函数
typedef Compare key_compare;
typedef Compare value_compare;
private:
// 内部采用RBTree作为底层容器
typedef rb_tree<key_type, value_type,
identity<value_type>, key_compare, Alloc> rep_type;
rep_type t; // 定义了一个RB_tree
public:
//typedef typename是用在模板里,告诉编译器,这是一个合法类型
typedef typename rep_type::const_pointer pointer;
typedef typename rep_type::const_pointer const_pointer;
typedef typename rep_type::const_reference reference;
typedef typename rep_type::const_reference const_reference;
typedef typename rep_type::difference_type difference_type;
// 设置成const迭代器,set的键值不允许修改
typedef typename rep_type::const_iterator iterator;
typedef typename rep_type::const_iterator const_iterator;
// 反向迭代器
typedef typename rep_type::const_reverse_iterator reverse_iterator;
typedef typename rep_type::const_reverse_iterator const_reverse_iterator;
typedef typename rep_type::size_type;
// 返回用于key比较的函数
key_compare key_comp() const { return t.key_comp(); }
// 由于set的性质, value比较和key使用同一个比较函数
value_compare value_comp() const { return t.key_comp(); }
// 声明了两个友元函数,重载了==和<操作符
friend bool operator== __STL_NULL_TMPL_ARGS (const set&, const set&);
friend bool operator< __STL_NULL_TMPL_ARGS (const set&, const set&);
}
set的插入一定要用RB_tree的insert_unique()而非insert_equal(),因为不允许相同的键值存在。multiset才用insert_equal( )
构造函数其一:
set(InputIterator first, InputIterator last)
: t(Compare()) { t.insert_unique(first, last);
set的操作
iterator begin() const { return t.begin(); }
iterator end() const { return t.end(); }
reverse_iterator rbegin() const { return t.rbegin(); }
reverse_iterator rend() const { return t.rend(); }
bool empty() const { return t.empty(); }
size_type size() const { return t.size(); }
size_type max_size() const { return t.max_size(); }
void swap(set<key,compare,Alloc>& x){t.swap(x.t)}
值得注意的就是删除和插入函数
注意不同版本之间的返回值和形参的不同
版本一:返回值为为一个pair对象
pair<iterator,bool>insert(const value_type& x)
{
pair<typename rep_type::iterator,bool> p = t.insert_unique(x);
return pair<iterator,bool>(p.first,p.second);
}
版本二:返回一个迭代器
iterator insert(iterator position,const value_type& x);
版本三:
void inset(inputIterator first,inputIterator last);
//返回小于当前元素可插入的第一个位置
iterator lower_bound(const key_type& x)const
//返回大于当前元素可插的第一个位置
iterator upper_bound(const key_type& x)const
//返回与指定键值相等的元素区间
pair<iterator,iterator> equal_range(const key_type& x)const
2、set相关算法
set有四个强大的算法,set_union(并集)、set_intersection(交集)、set_different(差集)、set_symmetric_different(对称差集)
首先看看如何应用的:
总之,在日常的使用中,set功能强大,遇到需要去重和排序的话,相当好用~~至于这四个set特有的函数,感兴趣的可以参考侯捷先生的《STL源码剖析》