关联容器支持通过键来高效地查找和读取元素。基本关联容器:map和set。set仅包含一个键。multimap和multiset支持同一个键多次出现在容器中。
10.1、引言:pair类型
pair类型,定义在utility头文件中。创建和初始化如:pair<T1,T2> p1(v1,v2);或make_pair(v1,v2)赋给pair类型的变量。
对于pair类型,也可考虑typedef简化其声明:如,typedef pair<string,string> Author;
对于pair类,可以直接访问其数据成员:其成员都是公有的。
10.3、map类型
在使用关联容器时,它的键不但有一个类型,而且还有一个相关的比较函数。默认情况下,标准库使用键类型定义的<操作符来实现键的比较。对于键类型,唯一的约束就是必须支持<操作符。
map<K,V>::value_type是存储元素的键以及值的pair类型,而且键为const(但它的值成员可以修改)。key_type是键类型;mapped_type是值类型;
用下标访问不存在的元素将导致在map容器中添加一个新的元素,它的键即为该下标值,如果没给该元素赋值,则值进行默认初始化,如int则初始化为0。
注:与vector和string类型不同,map下标操作符返回一个mapped_type类型的值,而map迭代器返回value_type类型的值,包含const key_type和mapped_type类型成员的pair对象。
10.3.5、map::insert的使用
map<string,int>word;
word["hello"]++;
pair<string,int> word2("hello",33);
word.insert(word2);//这边word2没有插入成功,word的hello值还是1。即在插入时,如果键在m中已经存在,则保持m不变。该函数返回一个pair类型对象,包含指向键为e.first的元素的map迭代器,以及一个bool类型的对象,表示是否插入了该元素,如:pair<map<string,int>::iterator, bool> ret=函数返回。++ret.first->second实现该值递增,->优先级高于++。
还有如:insert(beg,end);beg和end是标记元素范围的迭代器,即插入该范围内的所有元素,遵循前闭后开原则。
10.3.6、查找并读取map中的元素
m.count(k):返回m中k的出现次数。它对于map键来说,0,1可以反应一个键是否存在。
m.find(k):如果m容器中存在按k索引的元素,则返回指向该元素的迭代器。如果不存在,则返回超出末端迭代器。如用:find函数!= 容器.end()来判断。
10.3.7、从map对象中删除元素
map容器的erase操作返回void。而顺序容器的erase操作则返回一个迭代器,指向被删除元素后面的元素。
m.erase(b,e)从m中删除一段范围内的元素,遵循前闭后开原则。
10.3.8、map对象的迭代遍历
map同样提供begin和end运算。
10.4、set类型
以一段范围的元素初始化set对象,或在set对象中插入一组元素时,对于每个键,事实上都只添加了一个元素。
set中添加元素:(1)insert一个元素;(2)调用insert时,提供一对迭代器实参,插入其标记范围内所有的元素。
set中获取元素:(1)find运算,找到返回对应元素的迭代器,否则为end()迭代器。(2)count运算,返回1或0。
set的键也是const,不能通过找到的迭代器修改键值。
10.5、multimap和multiset类型
multimap不支持下标运算(显然,某个键对应多个值),其余与map操作相同。
10.5.1、元素的添加和删除
带有一个参数的erase版本将删除拥有该键的所有元素,并返回删除元素的个数。而带有一个或一对迭代器参数的版本只删除指定的元素,并返回void类型。
10.5.2、在multimap和multiset中查找元素
在multimap中,同一个键所关联的元素必然相邻存放。
案例:假设有作者与书名映射,希望找到并输出某个作者写的所有书的书名。方法一,使用find和count操作。首先调用count确定某作者所写的书籍数目,然后调用find获得指向第一个该键所关联的元素迭代器。方法二,用lower_bound(k)(返回一个迭代器,指向键不小于k的第一个元素)和upper_bound(k)(返回一个迭代器,指向键大于k的第一个元素)。如果该键没有关联的元素,则lower_bound和upper_bound返回相同的迭代器,都指向同一个元素或同时指向multimap的超出末端位置。它们都指向在保持容器元素顺序的前提下,该键应被插入的位置。equal_range(k)返回一个迭代器的pair对象,它的first成员等价于m.lower_bound(k),second成员等价于m.upper_bound(k)。
10.6、容器的综合应用:文本查询程序
设计程序的一个良好习惯是首先将程序所涉及的操作列出来。明确需要提供的操作,有助于建立需要的数据结构和实现这些行为。(看似常识,有时却不会去执行···)
问题:查询给出的单词所在的行号及每行内容
方法:(1)使用vector<string>类型的对象存储整个文件的副本,文件的每行是该对象的一个元素。在输出某一行时,只需以行号为下标获取该行所在的元素即可。(2)将每个单词所在的行号存储在一个set容器对象中。(3)使用一个map容器将 每个单词与一个 set 容器对象关联起来,该set容器对象记录此单词所在的行号。具体就是对每行的每个单词,用map[word].insert(行号);即可。