10.3
map 是键-值对的集合。map 类型通常可理解为关联数组(associativearray) :可使用键作为下标来获取一个值,正如内置数组类型一样。而关联的本质在于元素的值与某个特定的键相关联, 而并非通过元素在数组中的位置来获取。
在使用关联容器时, 它的键不但有一个类型, 而且还有一个相关的比较函数。默认情况下,标准库使用键类型定义的 < 操作符来实现键(key type)的比较。 在实际应用中,键类型必须定义 < 操作符,而且该操作符应能”正确地工作”,这一点很重要。
value_type 是存储元素的键以及值的 pair 类型,而且键为 const ,key_type在 map 容器中,用做索引的键的类型,mapped_type在 map 容器中,键所关联的值的类型在学习 map 的接口时,需谨记 value_type 是 pair 类型,它的值成员可以修改,但键成员不能修改。
10.3.4. 使用下标访问 map 对象
如下编写程序时:map <string, int> word_count; // empty map
// insert default initialzed element with key Anna; then assign 1 to its value
word_count["Anna"] = 1;
将发生以下事情:1. 在 word_count 中查找键为 Anna 的元素,没有找到。
2. 将一个新的键-值对插入到 word_count 中。它的键是 const string 类型的对象, 保存 Anna。 而它的值则采用值初始化, 这就意味着在本例中值为 0。
3. 将这个新的键-值对插入到 word_count 中。
4. 读取新插入的元素,并将它的值赋为 1。使用下标访问 map 与使用下标访问数组或 vector 的行为截然不同:用下标访问不存在的元素将导致在 map 容器中添加一个新元素,它的键即为该下标值。
下标行为的编程意义
// count number of times each word occurs in the input
map<string, int> word_count; // empty map from string to int
string word;
while (cin >> word)
++word_count[word];
10.3.5. map::insert 的使用
m.insert(e) | e 是一个用在 m 上的 value_type 类型的值。如果键 (e.first)不在 m 中,则插入一个值为 e.second 的新元素; 如果该键在 m 中已存在,则保持 m 不变。该函数返回一个 pair 类型对象,包含指向键为 e.first 的元素的 map 迭代器,以及一个 bool 类型的对象,表示是否插入了该元素 |
m.insert(beg,end) | beg 和 end 是标记元素范围的迭代器,其中的元素必须为 m.value_type 类型的键-值对。对于该范围内的所有元素, 如果它的键在 m 中不存在, 则将该键及其关联的值插入到 m。 返回 void 类型 |
m.insert(iter,e) | e 是一个用在 m 上的 value_type 类型的值。如果键 (e.first)不在 m 中,则创建新元素,并以迭代器 iter 为 起点搜索新元素存储的位置。返回一个迭代器,指向 m 中具 有给定键的元素 |
word_count.insert(map<string, int>::value_type("Anna", 1));
这是一个新创建的 pair 对象,将直接插入到 map 容器中。谨记 value_type是 pair<const K, V> 类型的同义词,K 为键类型,而 V 是键所关联的值的类型。
传递给 insert 的实参相当笨拙。可用两种方法简化:使用 make_pair:
word_count.insert(make_pair("Anna", 1));
typedef map<string,int>::value_type valType;
word_count.insert(valType("Anna", 1));
检测 insert 的返回值
// count number of times each word occurs in the input
map<string, int> word_count; // empty map from string to int string word;
while (cin >> word) {
// inserts element with key equal to word and value 1;
// if word already in word_count, insert does nothing
pair<map<string, int>::iterator, bool> ret =word_count.insert(make_pair(word, 1));
if (!ret.second) // word already in word_count
++ret.first->second; // increment counter
}
10.3.6. 查找并读取 map 中的元素
map<string,int> word_count;
int occurs = word_count["foobar"];
使用下标存在一个很危险的副作用:如果该键不在 map 容器中,那么下标操作会插入一个具有该键的新元素。 m.count(k) | 返回 m 中 k 的出现次数 |
m.find(k) | 如果 m 容器中存在按 k 索引的元素,则返回指向该元素的迭代器。如果不存在,则返回超出末端迭代器(第 3.4 节) |
10.3.7. 从 map 对象中删除元素
除此之外,map 类型还提供了一种额外的 erase 操作,其参数是 key_type类型的值,如果拥有该键的元素存在,则删除该元素。 erase 函数返回被删除元素的个数。对于 map 容器,该值必然是 0 或 1。如果返回 0,则表示欲删除的元素在 map 不存在。
10.4
set 容器只是单纯的键的集合。 两种例外包括:set 不支持下标操作符,而且没有定义 mapped_type 类型。在 set 容器中,value_type 不是 pair 类型,而是与 key_type 相同的类型。它们指的都是 set 中存储的元素类型。这一差别也体现了 set 存储的元素仅仅是键,而没有所关联的值。与 map 一样,set 容器存储的键也必须唯一,而且不能修改。
与 map 容器的操作一样,带有一个键参数的 insert 版本返回 pair 类型对象, 包含一个迭代器和一个 bool 值, 迭代器指向拥有该键的元素, 而 bool 值表明是否添加了元素。使用迭代器对的 insert 版本返回 void 类型。
正如不能修改 map 中元素的键部分一样,set 中的键也为 const。在获得指向 set 中某元素的迭代器后,只能对其做读操作,而不能做写操作:
// set_it refers to the element with key == 1
set<int>::iterator set_it = iset.find(1);
*set_it = 11; // error: keys in a set are read-only
cout << *set_it << endl; // ok: can read the key
10.5.2
m.lower_bound(k) | 返回一个迭代器,指向键不小于 k 的第一个元素 |
m.upper_bound(k) | 返回一个迭代器,指向键大于 k 的第一个元素 |
m.equal_range(k) | 返回一个迭代器的 pair 对象 它的 first 成员等价于 m.lower_bound(k)。而 second 成 员则等价于 m.upper_bound(k) |
若该键没有关联的元素,则 lower_bound 和 upper_bound 返回相同的迭代器:都指向同一个元素或同时指向 multimap 的超出末端位置。它们都指向在保持容器元素顺序的前提下该键应被插入的位置。
/* 10.26-29 */
#include<iostream>
#include<string>
#include<map>
#include<fstream>
#include<sstream>
using namespace std;
int main()
{
multimap<string,string> author;
string author_name,book_name;
ifstream open_file("text.txt");
if(!open_file)
{
cout<<"can't open it"<<endl;
return 0;
}
string line;
while(getline(open_file,line))
{
istringstream is(line);
while(is>>author_name)
{
while(is>>book_name)
author.insert(make_pair(author_name,book_name));
}
}
cout<<"input the author you want to delete:";
string erase_name;
cin>>erase_name;
pair<multimap<string,string>::iterator,multimap<string,string>::iterator> iter=author.equal_range(erase_name);
if(iter.first==iter.second)
cout<<"can't find "<<erase_name<<endl;
else
author.erase(iter.first,iter.second);
multimap<string,string>::iterator pre,cur;
pre=cur=author.begin();
for(;cur!=author.end();)
{
if(cur==author.begin())
cout<<"Author Names Beginning with '"<<(cur->first)[0]<<"':"<<endl;
if((cur->first)[0]!=(pre->first)[0])
cout<<"Author Names Beginning with '"<<(cur->first)[0]<<"':"<<endl;
pair<multimap<string,string>::iterator,multimap<string,string>::iterator> ret=author.equal_range(cur->first);
cout<<ret.first->first;
for(;ret.first!=ret.second;ret.first++)
cout<<","<<ret.first->second;
cout<<endl;
pre=cur;
cur=ret.second;
}
getchar();
getchar();
return 0;
}