C++primer笔记之关联容器

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 在这一章中,有以下的几点收获: 1、pair类型的使用相当频繁,如果需要定义多个相同的pair类型对象,可考虑利用typedef简化其声明: typedef pair A;这样,在后面的使用中就可以直接用A来代替前面繁琐的书写。

在这一章中,有以下的几点收获:

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 << "\t\t" << 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 << "\t(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 }

程序运行结果:

目录
相关文章
|
20天前
|
设计模式 存储 Android开发
c++的学习之路:18、容器适配器与反向迭代器
c++的学习之路:18、容器适配器与反向迭代器
21 0
|
2月前
|
Java 编译器 C++
C++入门指南:类和对象总结笔记(下)
C++入门指南:类和对象总结笔记(下)
30 0
|
2月前
|
存储 编译器 C语言
C++入门: 类和对象笔记总结(上)
C++入门: 类和对象笔记总结(上)
35 0
|
4天前
|
调度 C++ 容器
【C++】手搓 list 容器
本文我们实现了STL库中重要的list 的模拟实现,其中最重要莫过于迭代器的封装类的书写,这是前所未有的操作(对于我来说,我是第一次使用这种结构)。通过list 的模拟实现也帮我们巩固了类与对象的知识,也强化了指针操作的思路。欢迎大家讨论分析。
12 1
|
6天前
|
存储 设计模式 算法
【C++/STL】stack和queue(容器适配器、优先队列、双端队列)
【C++/STL】stack和queue(容器适配器、优先队列、双端队列)
13 1
|
12天前
|
存储 算法 C++
详解C++中的STL(标准模板库)容器
【4月更文挑战第30天】C++ STL容器包括序列容器(如`vector`、`list`、`deque`、`forward_list`、`array`和`string`)、关联容器(如`set`、`multiset`、`map`和`multimap`)和容器适配器(如`stack`、`queue`和`priority_queue`)。它们为动态数组、链表、栈、队列、集合和映射等数据结构提供了高效实现。选择合适的容器类型可优化性能,满足不同编程需求。
|
15天前
|
安全 Java 程序员
【C++笔记】从零开始认识继承
在编程中,继承是C++的核心特性,它允许类复用和扩展已有功能。继承自一个基类的派生类可以拥有基类的属性和方法,同时添加自己的特性。继承的起源是为了解决代码重复,提高模块化和可维护性。继承关系中的类形成层次结构,基类定义共性,派生类则根据需求添加特有功能。在继承时,需要注意成员函数的隐藏、作用域以及默认成员函数(的处理。此外,继承不支持友元关系的继承,静态成员在整个继承体系中是唯一的。虽然多继承和菱形继承可以提供复杂的设计,但它们可能导致二义性、数据冗余和性能问题,因此在实际编程中应谨慎使用。
17 1
【C++笔记】从零开始认识继承
|
19天前
|
存储 算法 程序员
C++从入门到精通:2.2.1标准库与STL容器算法深度解析
C++从入门到精通:2.2.1标准库与STL容器算法深度解析
|
26天前
|
C++ 容器
约瑟夫经典问题C++,STL容器queue解法
约瑟夫经典问题C++,STL容器queue解法
14 0
|
1月前
|
容器
C++map/multimap容器
C++map/multimap容器