C++(15)STL实践与分析之Map类型
来源:互联网 发布:js跳转页面弹出新页面 编辑:程序博客网 时间:2024/05/29 03:19
STL实践与分析
--map类型(上)
引:
map是键-值对的集合。map类型通常可以理解为关联数组:可以通过使用键作为下标来获取一个值,正如内置数组类型一样;而关联的本质在于元素的值与某个特定的键相关联,而并非通过元素在容器中的位置来获取。
一、map对象的定义
1、定义map对象时,必须分别指明键和值的类型:
- map<string,int> wordCnt;
map的构造函数
map<K,V>m;
创建一个名为m的空对象,其键和值的类型分别为K和V
map<K,V>m(m2);
创建m2的对象副本m,m和m2的键与值的类型必须完全一致
map<K,V>m(b,e);
创建map类型的对象m,存储迭代器b和e标记的范围内所有元素的副本。
迭代器元素的类型必须能转换为pair<constK, V>
2、键类型的约束
在使用关联容器时,它的键不但有一个类型,而且还有一个相关的比较函数。默认情况下,标准库使用键类型定义的<操作符来实现键(keytype)的比较。
对于键类型,唯一的约束就是必须支持<操作符,至于是否支持其他的关系或相等运算,则不作要求。
- //P310 习题10.5
- typedef list<int> lineNo;
- map<string,lineNo> word_line;
- //等同于
- map<string,list<int> > word_line;
二、map定义的类型
由于map对象的元素是键-值对,因此map对象的value_type是存储元素的键以及值类型的pair类型,而且键为const。
map类定义的类型
map<K,V>::key_type
在map容器中,用作索引的键类型
map<K,V>::mapped_type
在map容器中,键所关联的值类型
map<K,V>::value_type
一个pair类型:first元素具有
constmap<K,V>::key_type类型,而second元素则为map<K,V>::mapped_type类型
1、对map迭代器进行解引用将产生pair类型的对象
- map<string,int> word_count;
- word_count.insert(make_pair("C++ Primer",1));
- map<string,int>::iterator map_iter = word_count.begin();
- cout << map_iter -> first << " "
- << map_iter -> second << endl;
- map_iter -> first = "Effective C++"; //Error
- map_iter -> second = 3; //OK
2、map容器额外定义的类型别名
map类额外定义了两种类型:key_type和mapped_type,以获得键或值的类型。对于word_count,其key_type是string类型(注意不是conststring),而mapped_type则是int型。
- map<string,int> word_count;
- word_count.insert(make_pair("C++ Primer",1));
- map<string,int>::iterator map_iter = word_count.begin();
- map<string,int>::key_type first = map_iter -> first;
- map<string,int>::mapped_type second = map_iter -> second;
- first = "Effective C++";
- cout << first << " "
- << second << endl;
三、给map添加元素
添加元素:
1、可以使用insert成员实现;
2、或者先通过下标操作符获取元素,然后给获取的元素赋值。
四、使用下标访问map对象
- /** 该程序将发生下面几件事
- *1. 在 word_count 中查找键为 Anna 的元素,没有找到。
- *2. 将一个新的键-值对插入到 word_count 中。它的键是 const string 类型的对象,
- * 保存 Anna。而它的值则采用值初始化,这就意味着在本例中值为 0。
- *3. 将这个新的键-值对插入到 word_count 中。
- *4. 读取新插入的元素,并将它的值赋为 1。
- */
- map<string,int> word_count;
- word_count["Anna"] = 1;
- cout << word_count["Anna"] << endl;
- cout << word_count["anna"] << endl;
- cout << word_count.size() << endl;
使用下标访问map与使用下标访问数组或vector的行为截然不同:用下标访问不存在的元素将导致在map容器中添加一个新元素,它的键即为该下标值。
1、下表操作符返回值的使用
- //通常来说,下标操作符返回左值
- cout << word_count["Anna"] << endl;
- ++ word_count["Anna"];
- cout << word_count["Anna"] << endl;
有别于vector或string类型,map下标操作符返回的类型与对map迭代器进行解引用或的类型不同:map迭代器返回的是value_type类型的值– 包含constkey_type和mapped_type类型的pair对象;而下标操作符返回一个mapped_type类型的值。
2、使用下标行为的意义
对于map容器,如果下标所表示的键在容器中不存在,则添加新元素,这一特性可使程序惊人地简练:
- map<string,int> word_cnt;
- string str;
- while (cin >> str)
- {
- ++ word_cnt[str];
- }
- for (map<string,int>::iterator iter = word_cnt.begin(); iter != word_cnt.end(); ++iter)
- {
- cout << "First: " << iter -> first << "\tSecond: " << iter -> second << endl;
- }
- //P312 习题10.9
- int main()
- {
- freopen("input","r",stdin);
- map<string,int> word_cnt;
- string str;
- while (cin >> str)
- {
- ++ word_cnt[str];
- }
- cout << "Word:\t\tTimes:" << endl;
- for (map<string,int>::iterator iter = word_cnt.begin(); iter != word_cnt.end(); ++iter)
- {
- cout << iter -> first << "\t\t" << iter -> second << endl;
- }
- }
五、map::insert的使用
在map容器中,键影响了实参的类型,与vector的差别:
a.插入单个元素的insert版本使用键-值pair类型的参数。类似地,对于参数为一对迭代器的版本,迭代器必须指向键-值pair类型的元素。
b. map容器的接受单个值的insert版本的返回类型。
map容器提供的insert操作
m.insert(e)
e是一个用在m上的value_type类型的值。如果键(e.first)不在m中,则插入一个值为e.second的新元素;如果该键在m中已存在,则保持m不变。该函数返回一个pair类型对象,包含指向键为e.first的元素的map迭代器,以及一个bool类型的对象,表示是否插入了该元素
m.insert(b,e)
beg和end是标记元素范围的迭代器,其中的元素必须为m.value_type类型的键-值对。对于该范围内的所有元素,如果它的键在m中不存在,则将该键及其关联的值插入到m。返回void类型
m.insert(iter,e)
e是一个用在m上的value_type类型的值。如果键(e.first)不在m中,则创建新元素,并以迭代器iter为起点搜索新元素存储的位置。返回一个迭代器,指向m中具有给定键的元素
1、以insert代替下标运算
- //创建一个pair对象,将之直接插入到map容器中
- word_cnt.insert(map<string,int>::value_type("Anna",1));
使用insert成员可以有效的避免下标操作符带来的副作用:不必要的初始化。
传递给insert的实参相当笨拙,可以使用两种方法简化:
1)使用make_pair:
- word_cnt.insert(make_pair("Anna",1));
2)使用typedef:
- typedef map<string,int>::value_type valType;
- word_cnt.insert(valType("Anna",2));
2、检测insert的返回值
带有一个键-值pair形参的insert版本将返回一个值:包含一个迭代器和一个bool值的pair对象,其中迭代器指向map中具有相应键的元素,而bool值则表示是否插入了该元素。如果该键已在容器中,则其关联的值保持不变,返回的bool值为false,如果该键并不存在于容器中,则bool值为trul。在这两种情况下,迭代器都将指向具有给定键的元素。
- //重写前面的字符统计函数
- map<string,int> word_cnt;
- string word;
- while (cin >> word)
- {
- pair<map<string,int>::iterator,bool> res = word_cnt.insert(make_pair(word,1));
- if (!res.second)
- ++ res.first -> second;
- }
3、语法展开【解释上面的例程】
- pair<map<string,int>::iterator,bool> res = word_cnt.insert(make_pair(word,1));
对于:
- ++res.first -> second;
可以理解为:
- ++((res.first) -> second);
这个表达式一步步地展开解释:
1)res存储insert函数返回的pair对象。该pair的first成员是一个map迭代器,指向插入的键。
2)res.first从insert返回的pair对象中获取map迭代器。
3)res.first-> second对该迭代器进行解引用,获得一个value_type类型的对象。这个对象同样是pair类型的,它的second成员即为我们所添加的元素的值部分。
4)++res.first -> second实现该值的自增运算。
STL实践与分析
--map类型(下)
六、查找并读取map中的元素
map容器提供了两个操作:count和find,用于检查某个键是否存在而不会插入该键:
不修改map对象的查询
m.count(k)
返回m中k的出现次数
m.find(k)
如果m容器中存在k索引的元素,则返回指向该元素的迭代器。如果不存在,则返回超出末端的迭代器
1、使用count检查map对象中某键是否存在
因为map容器只允许一个键对应一个实例,所以,对于map对象,count成员的返回值只能是1或0。
如果返回值非0,则可以使用下标操作符来获取该键所关联的值,而不必担心这样会在map容器中插入新元素:
- int occurs = 0;
- if (word_cnt.count("Dream"))
- {
- occurs = word_cnt["Dream"];
- }
- cout << occurs << endl;
2、读取元素而不插入元素
- int occurs = 0;
- map<string,int>::iterator iter = word_cnt.find("Dream");
- if (iter != word_cnt.end())
- {
- occurs = iter -> second;
- }
- cout << occurs << endl;
- //P316 习题10.16
- map<string,vector<int> > str_vec;
- map<string,vector<int> >::iterator iter = str_vec.find("dream");
七、从map对象中删除元素
从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类型
- int remCount = 0;
- if (remCount = word_cnt.erase("Dream"))
- {
- cout << "Have removed " << remCount << " words" << endl;
- }
- else
- {
- cout << "Not found!" << endl;
- }
erase函数返回被删除元素的个数。对于map容器,该值必然是0或者1。如果返回0值,则表示该元素并不存在于map容器中。
八、map对象的迭代遍历
与其他容器一样,map同样提供了begin和end运算,以生成用于遍历整个容器的迭代器:
- cout << "First:\t\tSecond:" << endl;
- map<string,int>::iterator iter = word_cnt.begin();
- while (iter != word_cnt.end())
- {
- cout << iter -> first << "\t\t" << iter -> second << endl;
- ++ iter;
- }
或:
- cout << "First:\t\tSecond:" << endl;
- typedef map<string,int>::iterator mapIter;
- for (mapIter iter = word_cnt.begin(); iter != word_cnt.end(); ++iter)
- {
- cout << iter -> first << "\t\t" << iter -> second << endl;
- }
在使用迭代器遍历map容器时,迭代器指向的元素按照键的升序排列。
九、“单词转换”map对象
1、问题:
给出一个string对象,把它转换为另一个string对象。本程序的输入是两个文件。第一个文件包括了若干单词对,每对的第一个单词将出现在输入的字符串中,而第二个单词则是用于输出。本质上,这个文件提供的是单词转换的集合——在遇到第一个单词时,应该将之替换为第二个单词。第二个文件则提供了需要转换的文本。如果单词转换文件的内容是:
- 'em them
- cuz because
- gratz grateful
- i I
- nah no
- pos supposed
- sez said
- tanx thanks
- wuz was
2、测试样例
而要转换的文本是:
- nah i sez tanx cuz i wuz pos to
- not cuz i wuz gratz
则程序将产生如下输出结果:
- no I said thanks because I was supposed to
- not because I was grateful
4、思路:
将被替换的单词作为键,而用作的替换的单词则作为其相应要替换的值。
5、程序:
- #include <iostream>
- #include <sstream>
- #include <fstream>
- #include <map>
- using namespace std;
- int main()
- {
- ifstream inFile("input1");
- string line,firWord,secWord;
- map<string,string> convMap;
- while (getline(inFile,line))
- {
- istringstream strItem(line);
- while (strItem >> firWord >> secWord)
- {
- convMap.insert(make_pair(firWord,secWord));
- }
- }
- inFile.close();
- inFile.clear();
- inFile.open("input2");
- string word;
- while (getline(inFile,line))
- {
- istringstream strItem(line);
- while (strItem >> word)
- {
- map<string,string>::iterator iter = convMap.find(word);
- if (iter != convMap.end())
- {
- cout << iter -> second << ' ';
- }
- else
- {
- cout << word << ' ';
- }
- }
- cout << endl;
- }
- }
- //附上书上的原程序
- int main(int argc, char **argv)
- {
- map<string, string> trans_map;
- string key, value;
- if (argc != 3)
- throw runtime_error("wrong number of arguments");
- ifstream map_file;
- if (!open_file(map_file, argv[1]))
- throw runtime_error("no transformation file");
- while (map_file >> key >> value)
- 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))
- {
- istringstream stream(line);
- string word;
- bool firstword = true;
- while (stream >> word)
- {
- map<string, string>::const_iterator map_it =
- trans_map.find(word);
- if (map_it != trans_map.end())
- word = map_it->second;
- if (firstword)
- firstword = false;
- else
- cout << " ";
- cout << word;
- }
- cout << endl;
- }
- return 0;
- }
- //P319 习题10.18
- #include <iostream>
- #include <fstream>
- #include <string>
- #include <map>
- #include <vector>
- using namespace std;
- int main()
- {
- typedef string Family;
- typedef vector<string> Names;
- map<Family,Names> pepMap;
- Family first;
- string second;
- ifstream inFile("input");
- while (inFile >> first >> second)
- {
- Names child;
- pair<map<Family,Names>::iterator,bool> res = pepMap.insert(make_pair(first,child));
- res.first -> second.push_back(second);
- }
- inFile.close();
- inFile.clear();
- inFile.open("test");
- string searchFamily;
- while (inFile >> searchFamily)
- {
- map<Family,Names>::iterator iter = pepMap.find(searchFamily);
- if (iter == pepMap.end())
- {
- cout << "NO this Family name" << endl;
- }
- else
- {
- cout << iter -> first << ":" << endl;
- Names::iterator itName = iter -> second.begin();
- while (itName != iter -> second.end())
- {
- cout << *itName << endl;
- ++ itName;
- }
- cout << endl;
- }
- }
- }
本文借鉴:http://blog.csdn.net/column/details/zjf666.html?&page=4
- C++(15)STL实践与分析之Map类型
- C++(13)STL实践与分析之再谈String类型
- C++(12)STL实践与分析之顺序容器
- C++(14)STL分析与实践之容器适配器
- C++(16)STL实践与分析之初探算法
- C++(17)STL实践与分析之再谈迭代器
- C++STL之map
- [C++]STL之map
- C++STL 之map
- C++STL之map
- C++ Primer 学习笔记_36_STL实践与分析(10)--map类型(下
- C++STL之map学习
- C++STL之 map详解
- C++STL之map学习
- c++STL(四)关联容器set与map
- C++(21):STL初步之map初步
- C++map类型 之 简介
- C++STL map介绍与使用方法
- HDU-1686-Oulipo
- POJ 2752 Seek the Name, Seek the Fame
- hdu 5355 Cake dfs暴搜 构造
- Longest Valid Parentheses
- Myeclipse 自动生成hibernate实体类和映射文件步骤
- C++(15)STL实践与分析之Map类型
- c++类实现二分查找+二叉树查找
- c#ArrayList的用法
- 拓扑排序的bfs算法
- 详谈数据库的锁
- POJ- 3094 Quicksum-给规律求字符值
- 第11章:普通的登录功能
- 【线段树】 HDOJ 5361 In Touch
- iOS 设置NavigationBar和BarButtonItem的主题样式(iOS 6和iOS7适配)