1、标准库提供8个关联容器。
map | 关联数组;保存关键字-值对 |
---|---|
set | 只保存关键字 |
multimap | 关键字可重复的map |
multiset | 关键字可重复的set |
unordered_map | 用哈希函数组织的map |
unordered_set | 用哈希函数组织的set |
unordered_multimap | 哈希组织的map;关键字可重复 |
unordered_multiset | 哈希组织的set;关键字可重复 |
- 关联容器不支持顺序容器的位置相关的操作,例如push_back或push_front;原因是挂念容器中元素是根据关键字存储的,这些操作对关联容器没有意义。
- 关联容器的迭代器都是双向的。
2、关联容器定义和初始化
C c; | 默认构造函数 |
---|---|
C c1(c2) | 拷贝初始化 |
C c1 = c2 | 拷贝初始化 |
C c{a,b,c…} | 初始值列表初始化 |
C c = {a,b,c…} | 初始值列表初始化 |
C c(beg,end) | 迭代器初始化 |
- 初始化一个map时,必须提供关键字类型和值类型:{key, value}。
- 对于有序容器,map、multimap、set和multiset,关键字类型必须定义元素比较的方法。默认情况下,标准库使用关键字类型的 < 运算符来比较两个关键字。
3、容器关键字和值的类型;key_type,mapped_type,value_type
key_type | 此容器关键字类型 |
---|---|
mapped_type | 每个关键字关联的类型;只适用与map |
value_type | 对于set,与key_value相同;对于map,为pair<const key_type, mapped_type> |
- 关键字决定了排序,因此不允许改变,属于const类型。
- 一个map的value_type是一个pair,我们可以改变pair的值,但不能改变关键字成员的值。
- set的迭代器是const,可以用一个set迭代器读取元素的值,但不能修改。
4、关联容器与算法
- 通常不对关联容器使用泛型算法,关键字是const这一特性意味着不能将关联容器传递给修改或重排容器元素的算法,因为这类算法需要向元素写入值。
- 关联容器可用于只读取元素的算法,但是很多这类算法都要搜索序列,由于关联容器可以通过关键字进行快速查找,因此对其使用泛型算法几乎总是个坏主意。
- 实际编程中,如果我们真要对一个关联容器使用算法,要么是将它当作一个源序列,要么当作一个目的位置。
5、添加元素
c.insert(v) | v是value_type类型的对象,args用来构造一个元素 |
---|---|
c.emplace(args) | 对于map和set,只有当元素的关键字不在c中时才插入(或构造)元素。函数返回一个pair,包含一个迭代器,指向具有指定关键字的元素,以及一个指示插入是否成功的bool值。对于multimap和multiset,总会插入(或构造)给定元素,并返回一个指向新元素的迭代器 |
c.insert(beg,end) | beg和end是迭代器,表示一个c::value_type类型值的范围,函数返回void |
c.insert(initlist) | 插入初始值列表,函数返回void |
c.insert(p,v) | 类似insert(v),但将迭代器p作为一个提示,指示从哪里开始搜索新元素应该存储的位置,返回一个迭代器,指向具有给定关键字的元素 |
c.emplace(p,args) | 类似emplace(v),但将迭代器p作为一个提示,指示从哪里开始搜索新元素应该存储的位置,返回一个迭代器,指向具有给定关键字的元素 |
- inset(emplace)返回的值依赖于容器类型和参数,对于不包含重复关键字的容器,添加单一元素的insert(emplace)版本返回一个pair。pair的first成员是一个迭代器,指向具有给定关键字的元素,second成员是一个bool值,false表示关键字已在容器中,insert什么事情也不做;true表示关键字不存在,元素被插入容器中。
6、删除元素
c.erase(k) | 从c中删除每个关键字为k的元素,返回一个size_type值,指出删除的元素的数量 |
---|---|
c.erase§ | 从c中删除迭代器p指定的元素,返回一个指向p之后元素的迭代器 |
c.erase(beg,end) | 删除迭代器对beg,end所表示范围中的元素,返回e |
7、map的下标操作
c[k] | 返回关键字为k的元素;如果k不在c中,添加一个关键字为k的元素,对其进行值初始化 |
---|---|
c.at(k) | 访问关键字为k的元素,带参数检查;若k不在c中,抛出一个out_of_range异常 |
- 不能对一个multimap、unordered_multimap进行下标操作,因为这些容器中可能有多个值与一个关键字相关联。
- 对一个map使用下标操作,其行为与数组或vector上的下标操作很不相同,使用一个不在容器中的关键字作为下标,会添加一个具有此关键字的元素到map中。
8、访问元素
c.find(k) | 返回一个迭代器,指向第一个关键字为k的元素,若k不在容器中,则返回尾后迭代器 |
---|---|
count(k) | 返回关键字等于k的元素的数量,对于不允许重复关键字的容器,返回值永远是0或1 |
c.lower_bound(k) | 返回一个迭代器,指向第一个关键字不小于k的元素 |
c.upper_bound(k) | 返回一个迭代器,指向第一个关键字大于k的元素 |
c.equal_range(k) | 返回一个迭代器pair,表示关键字等于k的元素的范围。若k不存在,pair的两个成员均等于c.end() |
- lower_bound(k)和upper_bound(k)不适合用于无序容器。
9、无序容器
- 新标准定义了4个无序关联容器,这些容器不是使用比较运算符来组织元素,而是使用一个哈希函数(hash function)和关键字类型的==运算符。
- 无序容器在存储上组织为一组桶,每个桶保存零个或多个元素。无序容器使用一个哈希函数将元素映射到桶。
- 默认情况下,无序容器使用关键字类型的==运算符来比较元素,它们还使用一个hash<key_type>类型的对象来生成每个元素的哈希值。
- 标准库为内置类型(包括指针)提供了hash模板,我们可以直接定义关键字是内置类型(包括指针类型)、string还是智能指针类型的无序容器。
- 我们不能直接定义关键字类型为自定义类类型的无序容器,不能直接使用哈希模板,而必须提供我们自己的hash模板版本。