关联容器中的元素是按关键字来保存和访问的。
两个主要的关联容器类型是map和set。
一、使用关联容器
使用map
当从map中提取一个元素时,会得到一个pair类型的对象。pair是一个模板类型,保存两个名为first和second的(公有)数据成员。map所使用的pair用first成员保存关键字,用second成员保存对应的值。
使用set
举例:统计单词出现次数时,忽略常见单词
当需要保存特定的值集合——通常是满足/不满足某种要求的值集合,用set最为方便,比如黑名单。
二、关联容器概述
关联容器不支持顺序容器的位置相关的操作,例如push_front或push_back。关联容器也不支持构造函数或插入操作这些接受一个元素值和一个数量值的操作。关联容器的迭代器都是双向的。
1. 定义关联容器
每个关联容器都定义了一个默认构造函数,它创建一个指定类型的空容器。
我们也可以将关联容器初始化为另一个同类型容器的拷贝,或者是从一个值范围来初始化关联容器,只要这些值可以转化为容器所需类型就可以。
初始化multimap或multiset
multimap和multiset允许多个元素具有相同的关键字。
2. 关键字类型的要求
有序容器的关键字
有序容器要求关键字类型必须支持比较操作<。
可以提供自己定义的操作来代替关键字上的<运算符。比较函数的基本性质:
使用关键字类型的比较函数
用compareIsbn函数定义一个multiset。
3. pair类型
标准库类型pair定义在头文件utility中。
一个pair保存两个数据成员。当创建一个pair时,我们必须提供两个类型名,pair的数据成员将具有对应的类型。
与其他标准库类型不同,pair的数据成员是public的。两个成员分别命名为first和second。
创建pair对象的函数
三、关联容器操作
在一个map中,每个元素是一个pair对象,包含一个关键字和一个关联的值。由于我们不能改变一个元素的关键字,因此这些pair的关键字部分是const的。
1. 关联容器迭代器
set的迭代器是const的
与不能改变一个map元素的关键字一样,一个set中的关键字是const的。可以用一个set迭代器来读取元素的值,但不能修改。
遍历关联容器
map和set支持begin和end操作。我们可以用这些函数迭代器,然后用迭代器来遍历容器,
当使用一个迭代器遍历一个map、multimap、set或multiset时,迭代器按关键字升序遍历元素。
关联容器和算法
我们通常不对关联容器使用泛型算法。const这一特性意味着不能将关联容器传递给修改或重排容器元素的算法。关联容器可用于只读取元素的算法。
2. 添加元素
检测insert的返回值
insert(或emplace)返回的值依赖于容器类型和参数。对于不包含重复关键字的容器,添加单一元素的insert和emplace版本返回一个pair,告诉我们插入操作是否成功。pair的first成员是一个迭代器,指向具有给定关键字的元素;second成员是一个bool值,指出元素是插入成功还是已经存在于容器中。如果关键字已在容器中,则insert什么事也不做,且返回值中的vool部分为false。如果关键字不存在,元素被插入容器中,且bool值为bool。
向multiset或multimap添加元素
对允许重复关键字的容器,接受单个元素的insert操作返回一个指向新元素的迭代器。
3. 删除元素
4. map的下标操作
map和unordered_map容器提供了下标运算符和一个对应的at函数。set类型不支持下标。
当对一个map进行下标操作时,会获得一个mapped_type对象;但当解引用一个map迭代器时,会得到一个value_type对象。
map的下标运算符返回一个左值。由于返回的是一个左值,我们既可以读也可以写元素。
5. 访问元素
在multimap或multiset中查找元素
用lower_bound和upper_bound解决此问题:
调用equal_range解决此问题:
四、无序容器
无序容器使用哈希函数和关键字类型的==运算符来组织元素。
管理桶
无序容器在存储上组织为一组桶,每个桶保存零个或多个元素。无序容器使用一个哈希函数将元素映射到桶。无序容器的性能依赖于哈希函数的质量和桶的数量和大小,
如果一个桶中保存了很多元素,那么查找一个特定元素就需要大量比较操作。
无序容器提供了一组管理桶的操作。这些成员函数允许我们查询容器的状态以及在必要时强制容器进行重组。