您的位置:首页 > 编程语言 > C语言/C++

C++ primer【笔记】关联容器 map

2015-08-13 08:42 736 查看

1.pair对象

pair对象类型在 utility 头文件中定义。

表1.1 pair 类型提供的操作

pair< T1, T2 > p1;创建一个空的 pair 对象,它的两个元素分别是 T1 和 T2类型,采用值初始化
pair< T1, T2 > p1(v1,v2);创建一个 pair 对象,它的两个元素分别是 T1 和 T2 ,其中 first 成员初始化为 v1,而 second 成员初始化为 v2
make_pair(v1,v2);以 v1 和 v2 值创建一个新 pair 对象,其元素类型分别是v1 和 v2 的类型
p1 < p2两个 pair 对象之间的小于运算,其定义遵循字典次序:如果 p1.first < p2.first 或者 !(p2.first < p1.first) &&p1.second < p2.second,则返回 true
p1 == p2如果两个 pair 对象的 first 和 second 成员依次相等,则这两个对象相等。该运算使用其元素的 == 操作符
p.first返回 p 中名为 first 的(公有)数据成员
p.second返回 p 的名为 second 的(公有)数据成员
*

对于 pair 类,可以直接访问其数据成员:其成员都是仅有的,分别命名为 first 和 second。只需使用普通的点操作符——成员访问标志即可访问其成员

vector容器中的pair对象输出问题:

《c++ primer》习题 exercise 10.1的程序如下:

Exercise 10.1 编写程序读入一系列 string 和 int 型数据, 将每一组存储在一个 pair 对象中,然后将这些 pair 对象存储在 vector 容器里。

#include<iostream>
#include<vector>
#include<utility>
#include<string>
using namespace std;
int main(){
pair<string, int> p;
vector< pair<string, int> > vps;
string s;
int i;
while(cin >> s >> i){
p = make_pair(s, i);
vps.push_back(p);
}

for(vector< pair<string, int> >::iterator iter = vps.begin(); iter != vps.end(); ++iter)
cout << iter->first << " "  << (*iter).second << endl;
//  for(vector<string>::iterator iter = vs.begin(); iter != vs.end(); ++iter)
//      cout << *iter << endl;
return 0;
}


访问成员操作符
"."
优先级高于解引用操作符
"*"
,所以
(*iter).second
要加括号, 因为 iter 是指向 pair 对象的,所以同时可以使用
iter->first
访问pair 对象。

2.map对象

使用map对象必须包含map头文件,必须指明键和值得类型。

map< string, int > word_count;


表2.1 map的构造函数

map< k, v > m;创建一个名为 m 的空 map 对象, 其键和值的类型分别为 k 和 v
map< k, v > m(m2);创建 m2 的副本 m,m 与 m2 必须有相同的键类型和值类型
map< k, v > m(b,e);创建 map 类型的对象 m, 存储迭代器 b 和 e 标记的范围内所有元素的副本。元素的类型必须能转换为 pair
*

表2.2 map类定义的类型

map< K,V >::key_type在 map 容器中,用做索引的键的类型
map< K, V >::mapped_type在 map 容器中,键所关联的值的类型
map< K, V >::value_type一个 pair 类型,它的 first 元素具有const map::key_type 类型,而 second 元素则为 map::mapped_type 类型
*

在学习 map 的接口时,需谨记 value_type 是 pair 类型,它的值成员可以修改,但键成员不能修改。对迭代器进行解引用时,将获得一个引用,指向容器中一个 value_type 类型的值。对于 map 容器,其 value_type 是 pair 类型,它的 first 成员存放键,为const,而 second 成员则存放值。

给map容器添加元素,可使用 insert 成员实现;或者,先用下标操作符获取元素,然后给获取的元素赋值。

使用下标访问map:

map< string, int > word_count;
word_count["WB"] = 1;


将发生以下事情:

在 word_count 中查找键为 WB 的元素,没有找到。

将一个新的键-值对插入到 word_count 中。它的键是 const string 类型的对象, 保存 WB。 而它的值则采用值初始化, 这就意味着在本例中值为 0。

将这个新的键-值对插入到 word_count 中。

读取新插入的元素,并将它的值赋为 1。

使用下标访问 map 与使用下标访问数组或 vector 的行为截然不同:用下标访问不存在的元素将导致在 map 容器中添加一个新元素,它的键即为该下标值。

有别于 vector 或 string 类型,map 下标操作符返回的类型与对 map 迭代器进行解引用获得的类型不相同。显然,map 迭代器返回 value_type 类型的值——包含 const key_type 和apped_type 类型成员的 pair 对象;下标操作符则返回一个 mapped_type 类型的值。

map< string, int > word_count;
while (cin >> word)
++word_count[word];


这段程序创建一个 map 对象,用来记录每个单词出现的次数。while 循环每次从标准输入读取一个单词。如果这是一个新的单词,则在 word_count 中添加以该单词为索引的新元素。如果读入的单词已在 map 对象中,则将它所对应的值加 1。

表2.3 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 中具有给定键的元素
*

用 insert 代替下标运算:

word_count.insert(map<string,int>::value_type("WB", 1));


在添加新 map 元素时,使用 insert 成员可避免使用下标操作符所带来的副作用:不必要的初始化。带有一个键-值 pair 形参的 insert 版本将返回一个值:包含一个迭代器和一个 bool 值的 pair 对象,其中迭代器指向 map 中具有相应键的元素,而 bool 值则表示是否插入了该元素。如果该键已在容器中,则其关联的值保持不变,返回的 bool 值为 true。

使用下标查找 map 中的元素存在一个很危险的副作用:如果该键不在 map 容器中,那么下标操作会插入一个具有该键的新元素。map 容器提供了两个操作:count 和 find,用于检查某个键是否存在而不会插入该键。

表2.4 不修改 map 对象的查询操作

m.count(k)返回 m 中 k 的出现次数
m.find(k)如果 m 容器中存在按 k 索引的元素,则返回指向该元素的迭代器。如果不存在,则返回超出末端迭代器
*

表2.5 从 map 对象中删除元素

m.erase(k)删除 m 中键为 k 的元素。返回 size_type 类型的值,表示删除的元素个数
m.erase(p)从 m 中删除迭代器 p 所指向的元素。p 必须指向 m 中确实存在的元素,而且不能等于 m.end()。返回 void
m.erase(b,e)从 m 中删除一段范围内的元素, 该范围由迭代器对 b 和 e 标记。b 和 e 必须标记 m 中的一段有效范围: 即 b 和 e 都必须指向 m中的元素或最后一个元素的下一个位置。而且,b 和 e 要么相等(此时删除的范围为空),要么 b 所指向的元素必须出现在 e 所指向的元素之前。返回 void 类型
*

“单词转换”程序:这个程序求解的问题是:给出一个 string 对象,把它转换为另一个 string 对象。本程序的输入是两个文件。第一个文件包括了若干单词对,每对的第一个单词将出现在输入的字符串中, 而第二个单词则是用于输出。本质上,这个文件提供的是单词转换的集合——在遇到第一个单词时, 应该将之替换为第二个单词。第二个文件则提供了需要转换的文本。

#include<iostream>
#include<sstream>//string streams operation:istringstream,ostringstream,stringstream
#include<fstream>//files operation: ifstream, ofstream,fstream
#include<string>
#include<map>
#include<utility>
#include<vector>

using namespace std;
//open files
ifstream &open_file(ifstream &in, const string &file){
in.close(); //close it incase it was already open
in.clear();//clear any exiting errors
//if the open fails, the stream will be in an invalid state
in.open(file.c_str());
return in;//if open successfully, "in" will be attached to files. otherwise, it will be errors
}

int main(int argc, char *argv[]){
//arg[1] and argv[2] store two files to transfer words
ifstream map_file;
map<string, string> trans_map;//store wrod pairs
string key,value;
if(argc != 3) // incorrect command parameters
throw runtime_error("Wrong number of arguments");
if(!open_file(map_file, argv[1]))
throw runtime_error("no transformation files");
while(map_file >> key >> value)// insert strings of files into a map
trans_map.insert(make_pair(key, value));

ifstream input;
if(!open_file(input, argv[2]))
throw runtime_error("no input file");
string line;
while(getline(input, line)){//get text by line
//associate line with istringstream to read by word
istringstream stream(line);
string word;
bool firstword = true;//label the head of a line
while(stream >> word){
map<string, string>::const_iterator map_it = trans_map.find(word);
if(map_it != trans_map.end())//find successfully
word = map_it -> second;
if(firstword)
firstword = false;// do not need to insert a blank in the head of a line
else
cout << " ";
cout << word;
}
cout << endl;
}

return 0;
}


以上内容为学习笔记,摘选自《c++ primer》第四版
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: