C++primer学习笔记及作业答案之第十一章

这篇博客详细介绍了C++ Primer中第十一章关于关联容器的内容,包括map、multimap、set和multiset的定义、操作以及它们与顺序容器的区别。关联容器通过关键字高效查找和提取元素,支持对关键字的高效访问。博客还解答了多个课后习题,对比了map、vector、list、deque、set和list的特点,并提供了实例说明何时选择使用。此外,讨论了map与set、set与list之间的区别,并解释了在不同场景下如何选择合适的关联容器。
摘要由CSDN通过智能技术生成

笔记:

11.1 关联容器

类型map和multimap定义在头文件map中,set和multiset定义在头文件set中;无序容器则定义在unordered_map和unordered_set中。

11.2 关联容器概述

11.3 关联容器操作

我们通常不对关联容器使用泛型算法。

解引用关联容器的迭代器得到的是value_type的值的引用。

关联容器map迭代器的类型是pair类型,记得pair类型的第一个类型是const,即map关键字类型是const。

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

insert和下标运算符的区别:参考例题11.35。

下标运算符,只能用于map和unordered_map类型的非const对象。

总结:

关联容器支持通过关键字高效查找和提取元素。对关键字的使用将关联容器和顺序容器区分开来,顺序容器是通过位置访问元素的。

课后习题:

练习 11.1:描述map 和vector 的不同。

答:两类容器的根本差别在于,顺序容器中的元素是“顺序”存储的(链表容器中的元素虽然不是在内存中“连续”存储的,但仍然是按“顺序”存储的。)理解“顺序”的关键,是理解容器支持的操作形式以及效率。

对于vector这样的顺序容器,元素在其中按顺序存储,每个元素都有唯一对应的位置编号,所有操作都是按编号(位置)进行的。例如,获取元素,插入删除元素,遍历元素。底层的数据结构是数组、链表,简单但能保证上述操作的高效。对于依赖值的元素访问,例如查找给定值(find),在这种数据结构上的实现是要通过遍历完成的,效率不佳。

而map这种关联容器,就是为了高效实现“按值访问元素”这类操作而设计的。为了达到这一目的,容器中的元素是按关键字值存储的,关键字值与元素数据建立起对应关系,这就是“关联”的含义。底层数据结构是红黑树、哈希表等,可高效实现按关键字值查找、添加、删除元素等操作。

练习 11.2:分别给出最适合使用list 、vector、deque 、map 以及set 的例子。

答:若元素很小(例如int),大致数量预先可知,在程序运行过程中不会剧烈变化,大部分情况下只在末尾添加或删除需要频繁访问任意位置的元素,则vector可带来最高的效率。若需要频繁在头部和尾部添加或删除元素,则deque是最好的选择。

如果元素较大(如大的类对象),数量预先不知道,或是程序运行过程中频繁变化,对元素的访问更多是顺序访问全部或很多元素,则list很适合。

map适合对一些对象按它们的某个特征进行访问的情形。典型的例如按学生的名字来查询学生信息,即可将学生名字作为关键字,将学生信息作为元素值,保存在map中。

set就是集合类型,当需要保存特定的值集合(通常是满足/不满足某种要求的值的集合),用set最为方便。

练习 11.3:编写你自己的单词计数程序。

//练习 11.3
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <set>
#include <cstddef>       //size_t类型定义的头文件,sizt_t是与机器无关的无符号数

using namespace std;

int main(int argc, char *argv[])
{
	ifstream in(argv[1]);
	if (!in)
	{
		cout << "打开输入文件失败!" << endl;
		exit(1);
	}
	
	//从string到size_t的空map
	map<string, size_t> word_count;
	//不统计的单词的集合
	set<string> exclude = { "The", "But", "And", "Or", "An", "A",
		"the", "but", "and", "or", "an", "a" };

	string word;
	while (in >> word)
	{
		//单词不在不统计的集合里时,才统计
		if (exclude.find(word) == exclude.end())
		{
		++word_count[word];

		}
	}

	for (const auto &w : word_count)
		cout << w.first << " occurs " << w.second
		<< ((w.second > 1) ? " times" : " time") << endl;

	system("pause");
	return 0;
}

练习 11.4:扩展你的程序,忽略大小写和标点。例如, ”example.”、”example,和”Example”,应该递增相同的计数器。

//练习 11.4
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <set>
#include <cstddef>       //size_t类型定义的头文件,sizt_t是与机器无关的无符号数

using namespace std;

//编写一个函数,将单词中的大写全部转化为小写,标点符号全部去掉
string &trans(string &s)
{
	for (int p = 0; p < s.size(); p++)
	{
		if (s[p] >= 'A' && s[p] <= 'Z')
		{
			s[p] -= ('A' - 'a');
		}
		else if (s[p] == ',' || s[p] == '.')
		{
			s.erase(p, 1);
		}
	}
	return s;
}

int main(int argc, char *argv[])
{
	ifstream in(argv[1]);
	if (!in)
	{
		cout << "打开输入文件失败!" << endl;
		exit(1);
	}
	
	//从string到size_t的空map
	map<string, size_t> word_count;
	//不统计的单词的集合
	set<string> exclude = { "The", "But", "And", "Or", "An", "A",
		"the", "but", "and", "or", "an", "a" };

	string word;
	while (in >> word)
	{
		trans(word);
		//单词不在不统计的集合里时,才统计
		if (exclude.find(word) == exclude.end())
		{
		++word_count[word];

		}
	}

	for (const auto &w : word_count)
		cout << w.first << " occurs " << w.second
		<< ((w.second > 1) ? " times" : " time") << endl;

	system("pause");
	return 0;
}

练习 11.5:解释map 和set 的区别。你如何选择使用哪个?

答:当需要查找给定值所对应的数据时,应使用map,其中保存的是<关键字,值>对,按关键字访问值。

如果只需判定给定值是否存在时,应使用set,它只是简单的值的集合。

练习 11.6:解释set 和list 的区别。你如何选择使用哪个?

答:两者都可以保存元素集合。如果只需要顺序访问这些元素,或是按位置访问元素,那么应使用list。如果需要快速判定是否有元素等于给定值,则应使用set。

练习 11.7:定义一个map,关键字是家庭的姓,值是一个vector,保存家中孩子(们)的名。编写代码,实现添加新的家庭以及向己有家庭中添加新的孩子。

//练习 11.7
#include <iostream>
#include <string>
#include <vector>
#include <map>

using namespace std;

//如果新添加的家庭不在map中,则才添加这个新家庭
void add_family(map<string, vector<string>> &families, const string &family)
{
	if (families.find(family) == families.end())
	{
		families[family] = vector<string>();
	}
}

//向已有的家庭中添加新的孩子
void add_child(map<strin
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值