关联式容器是最常见的、也是最有用的容器。关联式容器其实是关联数组概念的扩展。
关联式容器依据特定的排序准则,自动为其元素排序。关联式容器中的元素都经过排序,是有序的。所有关联式容器都有一个可供选择的template参数。这个参数用以指明排序准则。排序准则是以函数形式体现的,用于比较元素值或键值。默认情况下以"operator<"进行比较排序。程序员也可以提供自定义的比较函数,从而定义出不同的排序准则。
通常关联式容器由二叉树数据结构实现的。在二叉树中,每个元素都有一个父节点和两个子节点;左子树的所有元素都比该元素的值小,右子树的所有元素都比该元素的值大。关联式容器的差别在于元素的类型以及处理重复元素的方式。关联式容器还能提供对元素的快速访问,但不能实现任意位置的操作。
主要的关联式容器包括set(集合)、multisets、maps(映射)和multimaps。其中set可视为一种特殊的map,其元素的值即键值。前两种容器是在<set>头文件中声明和定义,后两种容器是在<map>头文件中声明和定义的。
set是支持随机存取的容器,其键值和实值是同一个值。set型容器中的所有元素必须具有唯一值,即不能包含重复的元素。set型容器中的元素可以实现按照次序来存储一组数值,即在一个集合中元素既作为被存储的数据又作为数据的键值。multiset是另一种类型的容器,其键值和数据元素是同样的值。与set不同的是,它可以包含重复的元素。multiset对象也可以实现按照次序来存储一组数值。
map是一种包含成对数据的关联数组容器。成对数据中的一个值是实值,另一个值是用来寻找数据的键值。一个特定的关键值只能与一个元素相联系。map是排序结构体,键值是独一无二的。事实上,map的内部结构和set是一样的。set可以看作一种特殊的map,其键值和实值是同一个。multimap是一种允许出现重复键值的关联数组容器。与map对象不同,一个键值可以和多个元素相联系,multimap而且允许键值重复。
set/multiset
set和multiset会根据特定的排序准则自动将元素排序。该集合更像一个有序链表,其中的元素有顺序存储。
namespace std{
template<class T,
class Compare = less<T>,
class Allocator = allocator<T> >
class set;
template<class T,
class Compare = less<T>,
class Allocator = allocator<T> >
class multiset;
}
template参数
- T:只要assignable(可赋值)、copyable(可拷贝)、comparable(可比较)的型别T 都可成为set或multiset的元素。
- Compare: 第二个template参数用来定义排序准则,此参数可有可无,默认采用less(这是一个仿函数,以operator<对元素比较)。
- Allocator :内存模型。
排序准则
可采用两种形式:
- 在类模板中以参数形式实现
- 以构造函数参数定义
具体形式如下:
set<int,greater<int>> S1;//第一种形式实现排序规则
set<int> S2(less<int>());//第二种形式实现排序规则
排序准则需满足:
- 反对称;对于operator<而言,若x<y为真,则y<x为假。
- 可传递;对于operator<而言,若x<y且y<z为真,则x<z为真。
- 非自反;对于operator<而言,x<x恒为假。
set和multiset通常由平衡二叉树实现。内部结构如下图示:
因为自动排序使set和multiset有一个重要限制:不得随意改变元素的值,否则会打乱原有正确的排序。因此改变元素的值需要先删除旧元素,再插入新元素。
- set和multiset不提供直接存取元素的任何操作函数
- 通过迭代器可以进行元素间接存取。有一个限制:从迭代器的角度看元素值是常数。
set/multiset操作函数
1、构造函数和析构函数
操作 | 效果 |
---|---|
set c | 生成一个空的set/multiset,不含任何元素 |
set c(op) | 以op为排序准则,产生一个空的set/multiset |
set c1(c2) | 产生某个set/multiset的副本,所有元素均被复制 |
set c(beg,end) | 以区间[beg,end]内的元素产生一个set/multiset |
set c(beg,end,op) | 以op为排序准则,以区间[beg,end]内的元素产生一个set/multiset |
c.~set() | 销毁所有元素,释放内存 |
2、非变动性操作
操作 | 效果 |
---|---|
c.size() | 返回容器大小 |
c.empty() | 判断容器是否空 |
c.max_size() | 返回容器可容纳的最大元素数量 |
c1==c2 | 判断c1是否等于c2 |
c1!=c2 | 判断c1是否不等于c2 |
c1<c2 | 判断c1是否小于c2 |
c1>c2 | 判断c1是否大于c2 |
c1<=c2 | 判断c1是否小于等于c2 |
c1>=c2 | 判断c1是否大于等于c2 |
*比较操作只能用于型别相同的容器。
3、搜寻操作函数
操作 | 效果 |
---|---|
count(elem) | 返回元素值为elem的元素的个数 |
find(elem) | 返回元素值为elem的第一个元素的位置,没有的话返回end() |
lower_bound(elem) | 返回elem的第一个可安插位置,即元素值>=elem的第一个元素位置 |
upper_bound(elem) | 返回elem的最后一个可安插位置,即元素值>elem的第一个元素的位置 |
equal_bound(elem) | 返回elem可安插的第一个位置和最后一个位置,即元素值==elem的元素区间 |