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》第四版
相关文章推荐
- 黑马程序员-----------C语言基础-----------分支结构
- C++安全异常std:auto_ptr
- [转载] C++ 多线程编程总结
- VC++ 关于 ON_UPDATE_COMMAND_UI 相关的作用.
- C语言内存分配
- C语言的函数
- c++的类中typedef的作用
- hdu1598 有向边 并查集
- C++函数调用的完美灾难
- C++ 指针与引用 知识点 小结
- 在C#中调用C++写的DLL
- c++,为什么要引入虚拟继承
- C++之迭代器(iterator)与集合(vector)
- C++变量和基本类型笔记
- C语言-Switch 和case 的使用注意事项以及穿透效果的使用
- VS2010 C++ 学习笔记(一) 引用 函数参数默认值 函数重载 内联inline
- 在VC++6.0中给对话框设置背景色或者背景图片
- 【C++笔记】第二章
- 在c++中可以调用java中的方法,从而实现java与c++的的交互。
- C++ 数据的保护(const)