SGISTL源码阅读十九 set关联式容器
前言
之前我们已经分析了vector
,list
,deque
三个容器。如果按照“数据在容器中的排列”特性,容器可以分为序列式(sequence)和关联式(associative)两种,前面学习过的三种容器都是序列式容器。
接下来我们将学习关联式容器。标准的STL关联式容器分为set
(集合)和map
(映射表)两大类,以及这两大类的衍生体muiltiset
(多键集合)和multimap
(多键映射表),他们的底层机制均以RB-Tree
红黑树完成,红黑树是一种特殊的二叉查找树。在STL中RB-Tree
也是一个独立的容器,但是不开放对用户使用。
关于红黑树我们在这里不作过多介绍,但是红黑树的重要性是不言而喻的,这里只给出红黑树的特性。
- 每个节点都是黑色或者红色
- 根节点必须是黑色
- 每个叶子节点(NIL)是黑色
- 如果一个节点是红色的,那么它的子节点必须是黑色的
- 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑色节点
本次我们要分析的是set
集合,set
的特性是所有元素都会根据元素的键值自动被排列,(因为它的底层是红黑树)。set
的特殊之处是它元素的键值就是它的实值,实值就是键值。其实就是我们数学中学习到集合是一个意思,set
中的元素是保证唯一性但是不保证顺序性的。
深入源码
set
的定义部分
#ifndef __STL_LIMITED_DEFAULT_TEMPLATES
template <class Key, class Compare = less<Key>, class Alloc = alloc>
#else
template <class Key, class Compare, class Alloc = alloc>
#endif
class set {
public:
// typedefs:
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;
public:
//声明了相应型别
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::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 size_type;
typedef typename rep_type::difference_type difference_type;
通过源码我们可以看到它的底层确实是红黑树,并且缺省使用了STL的空间配置器。
set
的构造函数
因为使用了红黑树作为底层容器,相关的操作可以直接调用底层容器提供的方法。
#ifdef __STL_MEMBER_TEMPLATES
//迭代器指定范围构造
template <class InputIterator>
set(InputIterator first, InputIterator last)
: t(Compare()) { t.insert_unique(first, last); }
template <class InputIterator>
set(InputIterator first, InputIterator last, const Compare& comp)
: t(comp) { t.insert_unique(first, last); }
#else
//普通指针指定范围构造
set(const value_type* first, const value_type* last)
: t(Compare()) { t.insert_unique(first, last); }
set(const value_type* first, const value_type* last, const Compare& comp)
: t(comp) { t.insert_unique(first, last); }
set(const_iterator first, const_iterator last)
: t(Compare()) { t.insert_unique(first, last); }
set(const_iterator first, const_iterator last, const Compare& comp)
: t(comp) { t.insert_unique(first, last); }
#endif /* __STL_MEMBER_TEMPLATES */
操作符重载
//重载=,直接将底层的红黑树赋值即可
set(const set<Key, Compare, Alloc>& x) : t(x.t) {}
set<Key, Compare, Alloc>& operator=(const set<Key, Compare, Alloc>& x) {
t = x.t;
return *this;
}
//重载==
template <class Key, class Compare, class Alloc>
inline bool operator==(const set<Key, Compare, Alloc>& x,
const set<Key, Compare, Alloc>& y) {
return x.t == y.t;
}
//重载<
template <class Key, class Compare, class Alloc>
inline bool operator<(const set<Key, Compare, Alloc>& x,
const set<Key, Compare, Alloc>& y) {
return x.t < y.t;
}
set
的相关操作
基本操作
//比较键值
key_compare key_comp() const { return t.key_comp(); }
//比较实值
value_compare value_comp() const { return t.key_comp(); }
//返回set的起始迭代器
iterator begin() const { return t.begin(); }
//返回set的末尾迭代器
iterator end() const { return t.end(); }
reverse_iterator rbegin() const { return t.rbegin(); }
reverse_iterator rend() const { return t.rend(); }
//判断set是否为空
bool empty() const { return t.empty(); }
//返回set的大小
size_type size() const { return t.size(); }
size_type max_size() const { return t.max_size(); }
//互换两个set
void swap(set<Key, Compare, Alloc>& x) { t.swap(x.t); }
//...
iterator find(const key_type& x) const { return t.find(x); }
size_type count(const key_type& x) const { return t.count(x); }
//返回指向小于(或等于)某值的第一个元素的迭代器
iterator lower_bound(const key_type& x) const {
return t.lower_bound(x);
}
iterator upper_bound(const key_type& x) const {
return t.upper_bound(x);
}
pair<iterator,iterator> equal_range(const key_type& x) const {
return t.equal_range(x);
}
insert
插入操作
set
所有需要使用的方法红黑树都已经实现了,所以直接调用即可
//插入一个值为x的元素
typedef pair<iterator, bool> pair_iterator_bool;
pair<iterator,bool> insert(const value_type& x) {
//insert_unique,不允许重复的值
pair<typename rep_type::iterator, bool> p = t.insert_unique(x);
//返回pair(之后会讲到),第一个代表指向插入节点的迭代器,第二个代表插入是否成功
return pair<iterator, bool>(p.first, p.second);
}
iterator insert(iterator position, const value_type& x) {
typedef typename rep_type::iterator rep_iterator;
return t.insert_unique((rep_iterator&)position, x);
}
#ifdef __STL_MEMBER_TEMPLATES
template <class InputIterator>
void insert(InputIterator first, InputIterator last) {
t.insert_unique(first, last);
}
#else
void insert(const_iterator first, const_iterator last) {
t.insert_unique(first, last);
}
void insert(const value_type* first, const value_type* last) {
t.insert_unique(first, last);
}
erase
/clear
删除操作
void erase(iterator position) {
typedef typename rep_type::iterator rep_iterator;
t.erase((rep_iterator&)position);
}
size_type erase(const key_type& x) {
return t.erase(x);
}
void erase(iterator first, iterator last) {
typedef typename rep_type::iterator rep_iterator;
t.erase((rep_iterator&)first, (rep_iterator&)last);
}
void clear() { t.clear(); }
关于set
的操作总结
1. begin()--返回指向第一个元素的迭代器
2. clear()--清除所有元素
3. count()--返回某个值元素的个数
4. empty()--如果集合为空,返回true
5. end()--返回指向最后一个元素的迭代器
6. equal_range()--返回集合中与给定值相等的上下限的两个迭代器
7. erase()--删除集合中的元素
8. find()--返回一个指向被查找到元素的迭代器
9. get_allocator()--返回集合的分配器
10. insert()--在集合中插入元素
11. lower_bound()--返回指向大于(或等于)某值的第一个元素的迭代器
12. key_comp()--返回一个用于元素间值比较的函数
13. max_size()--返回集合能容纳的元素的最大限值
14. rbegin()--返回指向集合中最后一个元素的反向迭代器
15. rend()--返回指向集合中第一个元素的反向迭代器
16. size()--集合中元素的数目
17. swap()--交换两个集合变量
18. upper_bound()--返回大于某个值元素的迭代器
19. value_comp()--返回一个用于比较元素间的值的函数
set
的简单使用
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int> myset{0};
myset.insert(5);
myset.insert(2);
myset.insert(6);
//获取指向头尾的迭代器
set<int>::iterator first = myset.begin();
set<int>::iterator last = myset.end();
while(first != last)
{
cout << *first << endl;
first++;
}
myset.erase(myset.begin(), myset.end());
cout << "size:" << myset.size() << endl;
//尝试插入已存在的元素
//查找2的位置
set<int>::iterator ite1 = myset.find(2);
if(ite1 != myset.end())
{
cout << "i find it" << endl;
}
else
{
cout << "not found" << endl;
}
return 0;
}
关于multiset
multiset
和set
的特性和用法一致,唯一的差别就是multiset
允许键值重复。
这是因为调用红黑树的插入操作函数不同造成而造成的区别。set
调用的是insert_unique
函数而multiset
调用的是insert_equal
函数
深入源码
没有贴出全部源码,因为大部分和set
相同
iterator insert(const value_type& x) {
//调用的是insert_equal函数
return t.insert_equal(x);
}
iterator insert(iterator position, const value_type& x) {
typedef typename rep_type::iterator rep_iterator;
return t.insert_equal((rep_iterator&)position, x);
}
#ifdef __STL_MEMBER_TEMPLATES
template <class InputIterator>
void insert(InputIterator first, InputIterator last) {
t.insert_equal(first, last);
}
#else
void insert(const value_type* first, const value_type* last) {
t.insert_equal(first, last);
}
void insert(const_iterator first, const_iterator last) {
t.insert_equal(first, last);
}