C++ Primer 0x0B 练习题解

Posted 鱼竿钓鱼干

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ Primer 0x0B 练习题解相关的知识,希望对你有一定的参考价值。

📔 C++ Primer 0x0B 练习题解

更好的阅读体验(实时更新与修正)

推荐阅读 《C++ Primer 5th》知识点总结&练习题解

11.1 使用关联容器

11.1 描述mapvector的不同

  • map是关联容器,vector是顺序容器
  • 关联容器不支持顺序容器的位置相关的操作如push_frontpush_back
  • 关联容器的迭代器都是双向的,vector是随机迭代器

11.2 分别给出最适合使用listvectordequemap以及set的例子。

  • list:双向链表,适合频繁插入删除元素的场景。
  • vector:适合频繁访问元素的场景。
  • deque:双端队列,适合频繁在头尾插入删除元素的场景。
  • map:字典。
  • set:适合有序不重复的元素的场景。

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

#include <map>
#include <string>
#include <iostream>

int main()
	std::map<std::string,int>mp;
	std::string s;
	
	while(std::cin >> s)mp[s]++;
	
	for(const auto& e:mp)
		std::cout << e.first << " " << e.second << std::endl;
	
	return 0;

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

#include <cctype>
#include <map>
#include <string>
#include <iostream>
#include <algorithm>

int main()
	std::map<std::string,int>mp;
	std::string s;
	
	while(std::cin >> s)
		for(auto &c:s)c = tolower(c);
		s.erase(std::remove_if(s.begin(), s.end(),ispunct),s.end());
		++mp[s];
	
	
	for(const auto& e:mp)
		std::cout << e.first << " " << e.second << std::endl;
	
	return 0;

11.2 关联容器概述

11.2.1 定义关联容器

11.5 解释mapset的区别。你如何选择使用哪个?

  • 定义一个map,必须既指明关键字类型又指明值类型
  • 定义一个set,只需指明关键字类型,因为set中没有值

选择

  • map:字典。
  • set:适合有序不重复的元素的场景。

11.6 解释setlist的区别。你如何选择使用哪个?

set 关联容器,是有序不重复集合,底层实现是红黑树

list 顺序容器,是无序可重复集合,底层实现是链表

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

#include <cctype>
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>

int main()
	std::map<std::string,std::vector<std::string>>mp;
	std::string family_name,children_name;
	while(std::cin >> family_name >> children_name)
		mp[family_name].push_back(children_name);
	
	return 0;

11.8 编写一个程序,在一个vector而不是一个set中保存不重复的单词。使用set的优点是什么?

#include <cctype>
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>

int main()
	std::vector<std::string>words;
	std::string s;

	while(std::cin >> s)words.push_back(s);

	std::sort(words.begin(),words.end());
	words.erase(std::unique(words.begin(),words.end()),words.end());
	
	for(const auto &s:words)std::cout << s << std::endl;
	
	return 0;

set 本身就是有序不重复集合

11.2.2 关键字类型的要求

11.9 定义一个map,将单词与一个行号的list关联,list中保存的是单词所出现的行号。

std::map<std::string, std::list<std::size_t>> mp;

11.10 可以定义一个vector<int>::iteratorintmap吗?list<int>::iteratorintmap呢?对于两种情况,如果不能,解释为什么。

vector<int>::iteratorintmap,可以定义

list<int>::iteratorintmap,不可以定义

有序容器要求所提供的操作必须在关键字类型上定义一个严格弱序(可以自己定义)

因为map的键必须实现 < 操作,list 的迭代器不支持比较运算。

11.11 不使用decltype 重新定义 bookstore

multiset<Sales_data,bool (*)(const Sale_data&,const Sales_data&)>bookstore(compareIsbn);

11.2.3 pair 类型

11.12 编写程序,读入stringint的序列,将每个stringint存入一个pair 中,pair保存在一个vector中。

#include <cctype>
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>

int main()
	std::string s;int i;
	std::vector<std::pair<std::string,int>>v;

	while(std::cin >> s >> i)
		v.push_back(make_pair(s,i));
	
	for(auto p:v)
		std::cout << p.first << " " << p.second << std::endl;
	
	return 0;

11.13 在上一题的程序中,至少有三种创建pair的方法。编写此程序的三个版本,分别采用不同的方法创建pair。解释你认为哪种形式最易于编写和理解,为什么?

v.push_back(make_pair(s,i));
v.push_back(s,i);//最容易理解
v.push_back(std::pair<std::string,int>(s,i));

11.14 扩展你在11.2.1节练习中编写的孩子姓达到名的map,添加一个pairvector,保存孩子的名和生日。

#include <cctype>
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>

int main()
	std::map<std::string,std::vector<std::pair<std::string,std::string>>>mp;
	std::string family_name,children_name,birthday;
	while(std::cin >> family_name >> children_name >> birthday)
		mp[family_name].push_back(children_name,birthday);
	
	return 0;

11.3 关联容器操作

11.3.1 关联容器迭代器

11.15 对一个intvector<int>的map,其mapped_typekey_typevalue_type分别是什么?

  • mapped_typevector<int>的map
  • key_typeint
  • value_typepair<const int,vector<int>

11.16 使用一个map迭代器编写一个表达式,将一个值赋予一个元素。

#include <cctype>
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>

int main()
	std::map<int,int>mp=1,10,2,9,3,8;
	std::map<int,int>::iterator iter = mp.begin();
	std::cout << mp[1] << std::endl;
	(*iter).second = 1;
	std::cout << mp[1] << std::endl;
	iter->second = 2;
	std::cout << mp[1] << std::endl;

	return 0;

11.17 假定c是一个stringmultisetv 是一个stringvector,解释下面的调用。指出每个调用是否合法:

copy(v.begin(), v.end(), inserter(c, c.end()));
copy(v.begin(), v.end(), back_inserter(c));//不合法,multiset关联容器不支持push_back
copy(c.begin(), c.end(), inserter(v, v.end()));
copy(c.begin(), c.end(), back_inserter(v));

11.18 写出第382页循环中map_it 的类型,不要使用autodecltype

map<std::string,std::size_t>::const_iterator

注意迭代器是不能加const的,不要写成下面这样

cosnt map<std::string,std::size_t>::iterator

11.19 定义一个变量,通过对11.2.2节中的名为 bookstoremultiset 调用begin()来初始化这个变量。写出变量的类型,不要使用autodecltype

using compareType = bool (*)(const Sales_data &, const Sales_data &);
std::multiset<Sales_data, compareType> bookstore(compareIsbn);
std::multiset<Sales_data, compareType>::iterator c_it = bookstore.begin();

11.3.2 添加元素

11.20 重写11.1节练习的单词计数程序,使用insert代替下标操作。你认为哪个程序更容易编写和阅读?解释原因。

#include <map>
#include <string>
#include <iostream>

int main()
	std::map<std::string,int>mp;
	std::string s;
	
	while(std::cin >> s)
		auto result = mp.insert(s,1);
		if(!result.second)
			++result.first->second;
		
	
	
	for(const auto& e:mp)
		std::cout << e.first << " " << e.second << std::endl;
	
	return 0;

下标操作更容易

  • 对一个map使用下标操作,其行为与数组或vecotr上的下标操作很不相同,使用一个不在容器中的关键字作为下标,会添加一个具有此关键字的元素到map
  • c[k]返回关键字为k的元素,如果k不在c中则添加一个关键字为k的元素,对其值进行值初始化

11.21 假定word_count是一个stringsize_tmapword是一个string,解释下面循环的作用:

while (cin >> word)
	++word_count.insert(word, 0).first->second;

等价

while(cin >> word)
	++word_count[word];

11.22 给定一个map<string, vector<int>>,对此容器的插入一个元素的insert版本,写出其参数类型和返回类型。

  • 参数类型:std::pair<std::string,std::vector<int>

  • 返回类型:std::pair<std::map<std::string,std::vector<int>>::iterator,bool

11.23 11.2.1节练习中的map 以孩子的姓为关键字,保存他们的名的vector,用multimap 重写此map

#include <cctype>
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>

int main()
	std::multimap<std::string,std::string>mp;
	std::string family_name,children_name;
	while(std::cin >> family_name >> children_name)
		mp.emplace(family_name,children_name);
	
	return 0;

11.3.4 map的下标操作

11.24 下面的程序完成什么功能?

map<int, int> m;
m[0] = 1;//添加key-value:0-1

c[k]返回关键字为k的元素,如果k不在c中则添加一个关键字为k的元素,对其值进行值初始化

11.25 对比下面的程序与上一题程序

vector<int> v;
v[0] = 1;//下标越界访问

对一个map使用下标操作,其行为与数组或vecotr上的下标操作很不相同,使用一个不在容器中的关键字作为下标,会添加一个具有此关键字的元素到map

11.26 可以用什么类型来对一个map进行下标操作?下标运算符返回的类型是什么?请给出一个具体例子——即,定义一个map,然后写出一个可以用来对map进行下标操作的类型以及下标运算符将会返会的类型。

std::map<int, std::string> m =   1,"ss" , 2,"sz"  ;
using KeyType = std::map<int, std::string>::key_type;	
using ReturnType = std::map<int, std::string>::mapped_type;
  • map进行下标操作会得到一个mapped_type对象,解引用map迭代器时,会得到一个value_type对象,这与vectorstring是不同的
  • map的下标运算符返回的是一个左值,我们既可以读也可以写元素

11.3.5 访问元素

11.27 对于什么问题你会使用count来解决?什么时候你又会选择find呢?

允许重复用count不允许重复用find

11.28 对一个stringintvectormap,定义并初始化一个变量来保存在其上调用find所返回的结果。

#include <cctype>
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>

int main()
	std::map<std::string,std::vector<int>>mp="a",1,2,3,"ab",1,2,"abc",3,4;
	auto result = mp.find("abc");
	if(result != mp.end())
		std::cout << result->first << " " << std::endl;
		for(auto i:result->second)std::cout << i << " ";
	
	return 0;

11.29 如果给定的关键字不在容器中,upper_boundlower_boundequal_range 分别会返回什么?

  • c.lower_bound(k)返回一个迭代器,指向第一个关键字不小于k的元素,如果关键字不在容器中,则lower_bound会返回关键字的第一个安全插入点(不影响容器中元素顺序的插入位置)

  • 可以通过lower_boundupper_bound,获得一对迭代器对形成的范围,表示具有该关键字的元素的范围,如果没有与给定关键字匹配的元素,lower_boundupper_bound返回相同的迭代器

  • c.equal_range(k)返回一个迭代器pair表示关键字等于k的元素范围,若k不存在,pair的两成员均等于c.end()(两个关键字都指向可以插入的位置)

11.30 对于本节最后一个程序中的输出表达式,解释运算对象pos.first->second的含义。

  • c.equal_range(k)返回一个迭代器pair表示关键字等于k的元素范围,若k不存在,pair的两成员均等于c.end()(两个关键字都指向可以插入的位置)

pos是一个pair

pos.first是一个指向匹配关键字元素的迭代器

pos.first->second匹配关键字元素的关联也是个pair,访问这个pair的第二个成员

11.31 编写程序,定义一个作者及其作品的multimap。使用findmultimap中查找一个元素并用erase删除它。确保你的程序在元素不在map 中时也能正常运行。

#include <cctype>
#include <map>
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>

int main()
	std::multimap<std::string,std::string>authors
		"A","123","B","456","C","789",
		"A","abc","B","def","C","ghi"
	;
	auto found = authors.find("B");
	auto count = authors.count("B"<

以上是关于C++ Primer 0x0B 练习题解的主要内容,如果未能解决你的问题,请参考以下文章

C++ Primer 0x09 练习题解

C++ Primer 0x0D 练习题解

C++ Primer 0x03 练习题解

C++ Primer 0x08 练习题解

C++ Primer 0x04 练习题解

C++ Primer 0x07 练习题解