11.1 描述map
和vector
的不同。
答:
map
是关联容器, vector
是顺序容器。
11.2 分别给出最适合使用list
、vector
、deque
、map
以及set
的例子。
答:
list
:双向链表,适合频繁插入删除元素的场景。vector
:适合频繁访问元素的场景。deque
:双端队列,适合频繁在头尾插入删除元素的场景。map
:字典。set
:适合有序不重复的元素的场景。
11.3 编写你自己的单词计数程序。
答:
11.4 扩展你的程序,忽略大小写和标点。例如,"example."、"example,"和"Example"应该递增相同的计数器。
答:
11.5 解释map
和set
的区别。你如何选择使用哪个?
答:
map
是键值对,而 set
只有键没有值。当我需要存储键值对的时候使用 map
,而只需要键的时候使用 set
。
11.6 解释set
和list
的区别。你如何选择使用哪个?
答:
set
是有序不重复集合,底层实现是红黑树,而 list
是无序可重复集合,底层实现是链表。
11.7 定义一个map
,关键字是家庭的姓,值是一个vector
,保存家中孩子(们)的名。编写代码,实现添加新的家庭以及向已有家庭中添加新的孩子。
答:
11.8 编写一个程序,在一个vector
而不是一个set
中保存不重复的单词。使用set
的优点是什么?
答:
set
的优点是集合本身的元素就是不重复。
11.9 定义一个map
,将单词与一个行号的list
关联,list
中保存的是单词所出现的行号。
答:
11.10 可以定义一个vector<int>::iterator
到 int
的map
吗?list<int>::iterator
到 int
的map
呢?对于两种情况,如果不能,解释为什么。
答:
可以定义 vector<int>::iterator
到 int
的map
,但是不能定义 list<int>::iterator
到 int
的map
。因为map
的键必须实现 <
操作,list
的迭代器不支持比较运算。
11.12 编写程序,读入string
和int
的序列,将每个string
和int
存入一个pair
中,pair
保存在一个vector
中。
答:
注
11.13 在上一题的程序中,至少有三种创建pair
的方法。编写此程序的三个版本,分别采用不同的方法创建pair
。解释你认为哪种形式最易于编写和理解,为什么?
答:创建pair的3种方法
使用花括号的初始化器最易于理解和编写。
11.14 扩展你在11.2.1节练习中编写的孩子姓达到名的map
,添加一个pair
的vector
,保存孩子的名和生日。
答:
11.15 对一个int
到vector<int>的map
,其mapped_type
、key_type
和 value_type
分别是什么?
答:
mapped_type
:vector<int>
key_type
:int
value_type
:std::pair<const int,vector >
11.16
使用一个map
迭代器编写一个表达式,将一个值赋予一个元素。
答:
11.17 假定c
是一个string
的multiset
,v
是一个string
的vector
,解释下面的调用。指出每个调用是否合法:
copy(v.begin(), v.end(), inserter(c, c.end()));
copy(v.begin(), v.end(), back_inserter(c));
copy(c.begin(), c.end(), inserter(v, v.end()));
copy(c.begin(), c.end(), back_inserter(v));
答:
第二个调用不合法,因为 multiset
没有 push_back
方法。其他调用都合法。
11.18 写出第382页循环中map_it
的类型,不要使用auto
或 decltype
。
答:
11.20 重写11.1节练习的单词计数程序,使用insert
代替下标操作。你认为哪个程序更容易编写和阅读?解释原因。
答:
使用insert
更容易阅读和编写。insert
有返回值,可以明确的体现出插入操作的结果。
11.21 假定word_count
是一个string
到size_t
的map
,word
是一个string
,解释下面循环的作用:
答:
等价于
11.22 给定一个map<string, vector<int>>
,对此容器的插入一个元素的insert
版本,写出其参数类型和返回类型。
答:
11.23 11.2.1节练习中的map
以孩子的姓为关键字,保存他们的名的vector
,用multimap
重写此map
。
答:
11.24 下面的程序完成什么功能?
答:
添加一个元素到map
中,如果该键存在,则重新赋值。
11.25 对比下面的程序与上一题程序
答:
未定义行为,vector
的下标越界访问。
11.26 可以用什么类型来对一个map
进行下标操作?下标运算符返回的类型是什么?请给出一个具体例子——即,定义一个map
,然后写出一个可以用来对map
进行下标操作的类型以及下标运算符将会返会的类型。
答:
11.27 对于什么问题你会使用count
来解决?什么时候你又会选择find
呢?
答:对于允许重复关键字的容器,应该用 count
; 对于不允许重复关键字的容器,应该用 find
。
11.28 对一个string
到int
的vector
的map
,定义并初始化一个变量来保存在其上调用find
所返回的结果。
答:
11.29 如果给定的关键字不在容器中,upper_bound
、lower_bound
和 equal_range
分别会返回什么?
答:
如果给定的关键字不在容器中,则 lower_bound
和 upper_bound
会返回相等的迭代器,指向一个不影响排序的关键字插入位置。而equal_range
会返回一个 pair
,pair
中的两个迭代器都指向关键字可以插入的位置。
11.30 对于本节最后一个程序中的输出表达式,解释运算对象pos.first->second
的含义。
答:pos
是一个pair
,pos.first
是一个迭代器,指向匹配关键字的元素,该元素是一个 pair
,访问该元素的第二个成员。
11.31 编写程序,定义一个作者及其作品的multimap
。使用find
在multimap
中查找一个元素并用erase
删除它。确保你的程序在元素不在map
中时也能正常运行。
答:
11.32 使用上一题定义的multimap
编写一个程序,按字典序打印作者列表和他们的作品。
答:
11.33 实现你自己版本的单词转换程序。
答:
11.34 如果你将transform
函数中的find
替换为下标运算符,会发生什么情况?
答:
如果使用下标运算符,当关键字未在容器中时,会往容器中添加一个新元素。
11.36 我们的程序并没检查输入文件的合法性。特别是,它假定转换规则文件中的规则都是有意义的。如果文件中的某一行包含一个关键字、一个空格,然后就结束了,会发生什么?预测程序的行为并进行验证,再与你的程序进行比较。
答:
如果关键字没有对应的规则,那么程序会抛出一个 runtime_error
。
11.37 一个无序容器与其有序版本相比有何优势?有序版本有何优势?
答:
无序容器拥有更好的性能,有序容器使得元素始终有序。
11.38 用 unordered_map
重写单词计数程序和单词转换程序。
答: