在这一章中,有以下的几点收获:
1、pair类型的使用相当频繁,如果需要定义多个相同的pair类型对象,可考虑利用typedef简化其声明:
typedef pair<string, string> A;这样,在后面的使用中就可以直接用A来代替前面繁琐的书写。
2、三种方法创建pair对象:
(1)第一种方法:使用函数make_pair()
pair<string, string> spair;
string first, last;
while(cin >> first >> last) {
spair = make_pair(first, last);
}
(2)第二种方法:可以调用vector的构造函数
spair = pair<string, string> (first, last);
(3)第三种方法:由于pair的数据成员是公有的,所以可以直接输入
while(cin >> spair.first >> spair.last) { //}
三种方法个人用起来的话是第一种好用些,看个人喜好。
3、map定义的类型
map对应的元素是键-值对,在学习map接口时,警记value_type是pair类型,键是key_type类型,为const,不可修改,而值是mapped_type类型,可以修改。如下:
map<K,V>::key_type 键的类型
map<k,V>::mapped_type 值得类型
map<k,V>::value_type pair类型,first元素为const map<K,V>::key_type类型,second元素为map<K,V>::mapped_type类型
4、使用下标访问map对象
使用下标访问map与使用下标访问数组或vector的行为截然不同,用下标访问不存在的元素将导致在map容器中添加一个新的元素,它的键即为该下标值。
5、可以用insert代替下标运算,既简洁又紧凑
word.insert(map<string, int>::value_type("anna", 1));
其中红色部分代码可以用以下的两种方法代替:
word.insert(make_pair("anna",1));
typedef map<string, int>::value_type valType;
word.insert(valType("anna",1));
6、单词统计程序的两个版本:
第一版本:采用下标
1 string word; 2 map<string, int> wordCount; 3 4 //第一版本 5 while(cin >> word) { 6 ++ wordCount[word]; 7 }
第二版本:采用insert,利用返回值的第二个bool值来判断元素是否插入
1 string word; 2 map<string, int> wordCount; 3 4 //第二版本 5 while(cin >> word) { 6 pair< map<string, int>::iterator, bool > ret = 7 wordCount.insert(make_pair(word,1)); //!!!注意此句的表达 8 if (ret.second == false) //表明没有插入数据,map中已经存在着相应的单词 9 ++wordCount[word]; 10 }
7、与map容器不一样,set容器的每个键对应的元素是唯一的,不可重复。
8、在multimap和multiset中查找元素
可以用三种策略来解决查找问题:
第一种策略:使用find和count操作:
count函数求出某键出现的次数,而find操作则返回一个迭代器,指向第一个拥有正在查找的键的实例:
1 multimap<string, string> smmap; //创建作者和书名对应的multimap对象 2 string searchName("Wang"); //搜索的作者名 3 4 //第一种方法:采用find和count操作 5 typedef multimap<string, string>::size_type sz_type; 6 sz_type nCount = smmap.count(searchName); //得到searchName键对应的项的个数 7 multimap<string, string>::iterator it = smmap.find(searchName); 8 9 for (sz_type si = 0; si != nCount; ++ si, ++ it) 10 cout << it->second << endl;
第二种策略:采用面向迭代器的解决方案:
采用有关关联迭代器的操作:lower_bound和upper_bound
1 //第二种方法:采用面向迭代器的解决方案 2 typedef multimap<string, string>::iterator iter; 3 iter beg = smmap.lower_bound(searchName); 4 iter end = smmap.upper_bound(searchName); 5 while(beg != end) { 6 cout << beg->second << endl; 7 ++ beg; 8 }
第三种策略:采用equal_range函数
调用equal_range来代替upper_bound和lower_bound函数的效果是一样的
1 //第三种方法:采用equal_range函数 2 typedef multimap<string, string>::iterator iter; 3 pair<iter, iter> pos = smmap.equal_range(searchName); 4 while (pos.first != pos.second) { 5 //pos是一对迭代器,pos.first是第一个迭代器所关联的实例,而pos.first->second是该实例所对应的值 6 cout << pos.first->first << " " << pos.first->second << endl; 7 ++ pos.first; 8 }
9、容器的综合应用:文本查询程序
要求:给定一个文本文件,允许用户从该文件中查找单词,查询的结果是该单词出现的次数,并列出每次出现所在的行,如果某单词在同一行中多次出现,程序将只显示该行一次,行号按升序显示:
下面是程序的代码实现,详细实现细节可参考书本,首先看.h文件:
1 #ifndef _TEXTQUERY_H 2 #define _TEXTQUERY_H 3 4 /************************************************************************/ 5 /* 单词查找程序 6 /* 指定任意文本,并在其中查找单词 7 /* 结果为该单词出现的次数,并列出每次出现的行 8 /* 如果该单词在同一行中出现多次,将只显示该行一次,行号按升序显示 9 /************************************************************************/ 10 class TextQuery { 11 public: 12 typedef vector<string>::size_type line_no; //行号 13 void read_file(ifstream &is) { //从文件读入一行,并创建每个单词对应行号的map容器 14 store_file(is); 15 build_map(); 16 } 17 set<line_no> run_query(const string &) const; //返回包含string对象的所有行的行号 18 string text_line(line_no) const; //返回某行号所对应的文本行 19 private: 20 21 void store_file(ifstream &); //读入文件的每一行并存入vector中 22 void build_map(); //将每一行分解成各单词,同时记录该单词出现的行号 23 private: 24 vector<string> lines_of_text; 25 map < string, set<line_no> > word_map; 26 }; 27 28 // void TextQuery::read_file(ifstream &is) 29 // { 30 // store_file(is); 31 // build_map(); 32 // } 33 34 set<TextQuery::line_no> TextQuery::run_query(const string &str) const 35 { 36 map< string, set<line_no> >::const_iterator loc = word_map.find(str); 37 if (loc == word_map.end()) 38 return set<line_no>(); //没有找到,则返回空的set集 39 else 40 return loc->second; 41 } 42 43 string TextQuery::text_line(line_no line) const 44 { 45 if (line < lines_of_text.size()) 46 return lines_of_text[line]; 47 throw out_of_range("line number out of range"); 48 } 49 50 void TextQuery::store_file(ifstream &infile) 51 { 52 string line; 53 while(getline(infile, line)) 54 lines_of_text.push_back(line); 55 } 56 57 void TextQuery::build_map() 58 { 59 for(line_no linenum = 0; linenum != lines_of_text.size(); ++ linenum) { 60 istringstream issrem(lines_of_text[linenum]); 61 string word; 62 while (issrem >> word) { 63 word_map[word].insert(linenum); //下标插入法 64 } 65 } 66 } 67 68 #endif//_TEXTQUERY_H
下面是.cpp文件
1 #include "stdafx.h" 2 #include <iostream> 3 #include <map> 4 #include <set> 5 #include <vector> 6 #include <sstream> 7 #include <fstream> 8 #include <string> 9 10 using namespace std; 11 #include "TextQuery.h" 12 #include "fileio.h" 13 14 /************************************************************************/ 15 /* 文本查询程序(TextQuery.h) 16 /* Author:bakari Date:2013.9.20 17 /************************************************************************/ 18 19 void print_result(const set<TextQuery::line_no> &locs, 20 const string &s, const TextQuery &file);//打印结果 21 string make_plural(size_t size, const string &str, const string &endstr);//根据size的值打印单数还是复数 22 23 int main(int argc, char **argv) 24 { 25 ifstream infile; 26 27 if (argc < 2 || !open_file(infile,argv[1])) { 28 cerr << "no input file" << endl; 29 return EXIT_FAILURE; 30 } 31 TextQuery tq; 32 tq.read_file(infile); 33 34 while(true) { 35 cout << "enter word to look for or q to quit!" << endl; 36 string s; 37 cin >> s; 38 if (!cin || s == "q") 39 break; 40 set<TextQuery::line_no> locs = tq.run_query(s); 41 print_result(locs, s, tq); 42 } 43 return 0; 44 } 45 46 void print_result(const set<TextQuery::line_no> &locs, 47 const string &s, const TextQuery &file) 48 { 49 typedef set<TextQuery::line_no> line_num; 50 line_num::size_type size = locs.size(); //记录locs中每个单词出现的总次数 !!!注意表达 51 if (!size) { //没有该单词出现 52 cout << "no this word!" << endl; 53 exit(EXIT_FAILURE); 54 } 55 56 cout << s << " occurs " << size << make_plural(size, " time", "s") << endl; 57 for (line_num::const_iterator iter = locs.begin(); iter != locs.end(); ++iter) { 58 cout << " (line " << *iter + 1 << ") "; 59 cout << file.text_line(*iter) << endl; 60 } 61 62 } 63 64 string make_plural(size_t size, const string &str, const string &endstr) 65 { 66 return (size == 1)?str : str + endstr; 67 }
程序运行结果: