第十章关联容器
关联容器支持通过键来高效地查找和读取元素。
10.1 引言:pair类型
pair类型在utility头文件中定义。pair包含两个数值,也是一种模板类型,在创建pair对象时,必须提供两个类型名:pair对象所包含的两个数据成员各自对应的类型名字,这两个类型不必相同。
创建pair类型 | pair<T1, T2> p1 | 创建一个空的pair对象,两个元素分别是T1类型和T2类型,采用值初始化 |
pair<T1, T2> p1(v1, v2) | 创建一个pair对象,并且first成员初始化为v1,second成员初始化为v2 | |
生成新的pair对象 | make_pair(v1, v2) | 以v1和v2值创建一个新的pair对象,元素类型分别是v1和v2的类型 |
访问pair数据成员 | p.first | 返回first成员 |
p.second | 返回second成员 | |
pair对象关系运算 | p1 < p2 | 遵循字典次序 |
p1 == p2 | pair对象的first和second成员依次相等 |
10.2 关联容器
关联容器共享了大部分顺序容器的操作,但不提供front、push_front、pop_front、back、push_back以及pop_back操作。
10.3 map类型
必须包含map头文件:#include<map>
10.3.1 map对象的定义
map是键-值对的集合,map类型通常可理解为关联数组。定义map对象时,必须指明键和值的类型:
map<string,int> word_count; //键的类型是string,关联值的类型是int
map<k, v> m; | 创建一个名为m的空map对象 |
map<k, v> m(m2); | 创建m2的副本m,m与m2必须有相同的键值类型 |
map<k, v> m(b, e); | 创建map类型的对象m,存储迭代器b和e范围内的所有元素的副本,b和e必须是指向pair类型的迭代器 |
键的类型必须定义 <操作符,也是唯一约束,而且该操作符应能正确工作,比较函数必须在键类型上定义严格弱排序。因为关联容器中元素是按顺序(键排序)存储的。
10.3.2 map定义的类型
map<K, V>::key_type | 用作索引的键的类型 |
map<K, V>::mapped_type | 键所关联的值的类型 |
map<K, V>::value_type | 一个pair类型,它first元素是const key_value类型,不可修改,second元素是mapped_type |
10.3.3 给map添加元素
给容器添加键-值元素对,可以使用insert实现,或者使用下标操作。
10.3.4 使用下标访问map对象
map<string,int> word_count;
word_count[“Anna”]= 1; //原容器中不存在”Anna”键,将添加新pair对象作为元素
使用下标访问map与使用下标访问数组或vector的行为截然不同:下标访问不存在的元素将导致在map容器中添加一个新的元素,键为下标值。下标存在的话与数组操作类似。map迭代器返回的是value_type类型,是一个pair对象。下标操作符返回一个mapped_type类型。
10.3.5 map::insert的使用
m.insert(e) | e是一个m上的value_type类型的值。如果键e.first不存在,则插入元素e;如果键已存在,则保持m不变。 函数返回一个pair类型对象,分别包含指向键为e.first的元素的map迭代器,以及一个bool类型的对象,表示是否插入了该元素 |
m.insert(beg, end) | beg和end是标记元素范围的迭代器,其中的严肃必须为m.value_type类型。返回void类型 |
m.insert(iter, e) | 如果键e.first不在m中,则创建新元素,并以迭代器iter为起点搜索新元素存储的位置。返回一个迭代器,指向m中具有给定键的元素 |
pair<map<string,int>::iterator, bool> ret =word_count.insert(make_pair(word, 1));
10.3.6 查找并读取map元素
m.count(k) | 返回m中k的出现次数 |
m.find(k) | 如果m中存在按k索引的元素,则返回指向该元素的迭代器。如果不存在,则返回超出末端的迭代器 |
10.3.7 从map对象中删除元素
m.erase(k) | 删除m中键为k的元素,返回size_type类型的值,表示删除的元素个数。若不存在,则返回0。map容器必然是0或1 |
m.erase(k) | 删除迭代器p所指向的元素,p必须指向m中确实存在的元素,并且不能等于m.end()。返回void类型 |
m.erase(b, e) | 删除迭代器b和e范围内的元素。返回void类型 |
10.3.8 map对象的迭代遍历
map同样提供begin和end运算。
map<string,int>::const_iterator map_it =word_count.begin();
10.3.9 “单词转换”map对象
程序示例。
10.4 set类型
set容器只是单纯的键的集合,不支持下标操作,且没有定义mapped_type类型,其key_type与value_type都是键类型。
必须包含头文件:#include<set>
10.4.1 set容器的定义与使用
set容器的每个键都只能对应一个元素,类似数学的集合概念。
set<string> set1; //定义一个空的set容器
set<int> iset(ivec.begin(), ivec.end() ); //定义并初始化iset容器,并且用vector
类型对象ivec的元素初始化,注意的是对于每个键,只添加一次元素
set1.insert(“the”); //插入键,返回一个pair类型对象:一个指向拥有该键的元素的迭代器和一个表示是否添加成功的bool值
iset.insert( ivec2.begin(), ivec2.end() ); //插入一组元素,返回void
iset.find(11); //返回指向该元素的迭代器,否则返回iset.end()
iset.count(11); //返回个数0或1
set中的键也是const,不能修改,获取迭代器后只能读取,不能写入。
10.4.2 创建“单词排除”集
程序示例。
10.5 multimap和multiset类型
multimap和multiset类型允许一个键对于多个实例。multimap类型不支持下标操作。
头文件分别为<map>和<set>。
10.5.1 元素的添加和删除
每次insert都会添加一个元素。
带有一个键参数的erase版本将删除拥有该键的所有元素,并返回size_type类型,删除元素的个数。而带有一个或一对迭代器参数的版本只删除指定的元素,并返回void类型。
10.5.2 在multimap和multiset中查找元素
map和set的元素时按顺序存储的,multimap和multiset也是如此。因此,在multimap和multiset中,如果某个键对应多个实例,则这些实例在容器中将相邻存放。
要求输出某个键对应的所有元素,有3个策略:
(1)使用find和count操作
count返回某键出现次数,find返回指向第一个拥有查找元素的迭代器。循环就可以实现输出所有相应元素。
(2)使用特别的迭代器操作
m.lower_bound(k) | 返回一个迭代器,指向键不小于k的第一个元素 |
m.upper_bound(k) | 返回一个迭代器,指向键大于k的第一个元素 |
m.equal_range(k) | 返回一个pair对象,第一个元素时m.lower_bound(k),第二个元素是m.upper_bound(k) |
multimap<string,string> authors;
typedef multimap<string, string>::iterator authors_it;
authors_it beg = authors.lower_bound(serach_item);
authors_it end = authors. upper_bound(serach_item);
while(beg != end) {
cout<< beg -> second << endl;
++beg;
}