前言
这些大部分都是自己做出来的,小部分参考了答案,可供大家参考
11.1节练习
11.1:描述map和vector的不同
答:
map是表示哈希表,vector相当于数组
11.2:分别给出最适合使用list、vector、deque、map、以及set的例子
答:
list适用于链表,vector适用于数组类,deque是双端队列,map是哈希表,set是集合
11.3:编写你自己的单词计数程序
11.4:扩展你的程序,忽略大小写和标点,
答:上面两题一起
//map是表示哈希表,vector相当于数组
//list适用于链表,vector适用于数组类,deque是双端队列,map是哈希表,set是集合
#include<iostream>
#include<algorithm>
#include<map>
#include<unordered_map>
using namespace std;
unordered_map<string, int>mp;
int main() {
string str;
while (cin>>str) {
for (int i = 0;i < str.size();i++) {
if (str[i] >= 'A' && str[i] <= 'Z') {
str[i] += 32;
}
if (iswpunct(str[i]) ){
str.erase(str.begin() + i);
}
}
mp[str]++;
}
for (auto num : mp) {
cout << num.first << " ";
cout << num.second << endl;
}
return 0;
}
11.2.1节练习
11.5:解释map和set的区别,你应该选择哪个
答:map是哈希表,set是集合
11.6:解释set和list的区别
答:map是哈希表,list是链表
11.7:定义一个map,关键字是家庭的姓,值是一个vector,保存家中孩子们的明。编写代码,实现添加新的家庭以及向已有的家庭添加新的孩子。
答:
//map是表示哈希表,vector相当于数组
//list适用于链表,vector适用于数组类,deque是双端队列,map是哈希表,set是集合
#include<iostream>
#include<algorithm>
#include<map>
#include<unordered_map>
using namespace std;
unordered_map<string, vector<string>>mp;
void add_family(string name,vector<string>son) {
mp[name] = son;
}
void add_son(string family, string son_name) {
mp[family].emplace_back(son_name);
}
int main() {
string str;
vector<string>name = { "jone","job" };
add_family("mr", name);
add_son("mr", "hello");
return 0;
}
11.8:编写一个程序,在一个vector而不是一个set中保存不重复的单词,使用·set的优点是啥
答:
//map是表示哈希表,vector相当于数组
//list适用于链表,vector适用于数组类,deque是双端队列,map是哈希表,set是集合
#include<iostream>
#include<algorithm>
#include<map>
#include<unordered_map>
using namespace std;
unordered_map<string, vector<string>>mp;
void add(vector<int>& ans,int num) {
if (ans.empty()) {
ans.emplace_back(num);
return;
}
else
for (auto curr : ans) {
if (curr == num)return;
}
ans.emplace_back(num);
}
int main() {
int num;
vector<int>ans;
while (cin>>num) {
add(ans, num);
}
for (auto& num : ans)cout << num << " ";
return 0;
}
**set的效率更高**
11.9节练习
11.9:定义一个map,将单词与一个行号的list相关联,list保存的是单词所出现的行号。
11.10:可以定义一个vector< int> ::iterator到int的map吗,list< int >::iterator到int的map呢
答:
前一个可以,后一个不可以,map是有序的,则其关键字需要支持有序
11.11:不使用decltype重新定义bookstore
答:
typedef bool (*pf)(const sale_data&, const sale_data&);
multiset<sale_data, pf>bookstore(pf);
11.12:编写程序,读入string和int的序列,将每个string和int存入一个pair中,pair保存在一个vector
答:
#include<iostream>
#include<algorithm>
#include<map>
#include<unordered_map>
#include<set>
using namespace std;
int main() {
string str;
int num;
vector<pair<string, int>>ans;
while (cin >> str && cin >> num) {
pair<string, int>temp(str, num);
ans.emplace_back(temp);
cout << ans.back().first << " " << ans.back().second;
}
return 0;
}
11.13:在上一题的程序中,至少有三种创建pair的方法。编写此程序的三个版本,分别采用不同的方法创建pair。解释你认为哪种形式比较易于理解
答:
pair<string, int>temp(str, num);
pair<string, int>temp = { str,num };
ans.emplace_back(make_pair(str, num));
第一种比较好理解吧
11.14:扩展你的374页编写的孩子姓到名的map,添加一个pair的vector,保存孩子的名和生日
答:
#include<iostream>
#include<algorithm>
#include<map>
#include<unordered_map>
using namespace std;
unordered_map<string, vector<pair<string,int>>>mp;
void add_family(string name, vector<pair<string,int>>son) {
mp[name] = son;
}
void add_son(string family, string son_name,int age) {
mp[family].emplace_back(make_pair(son_name, age));
}
int main() {
string str;
vector<pair<string, int>>child = { make_pair("name",17) };
add_family("mr", child);
add_son("mr", "hello",34);
for (auto num : mp) {
cout << num.first << " ";
for (auto curr : num.second) {
cout << curr.first << " " << curr.second << " ";
}
}
return 0;
}
11.3.1节练习
11.15:对一个int到vector< int > 的mp,其mapped_type、key_type和value_tyep分别是什么
答:mapped_type是vector< int> 类型,key_type是int,value_type是pair<int,mapped_type>类型
11.16:使用一个map迭代器编写一个表达式,将一个值赋予一个元素。
答:
#include<iostream>
#include<algorithm>
#include<map>
#include<unordered_map>
using namespace std;
unordered_map<string, vector<pair<string,int>>>mp;
int main() {
map<int, int>ans = { {1,2} };
ans.begin()->second = 4;
for (auto num : ans)cout << num.second;
return 0;
}
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));
答:1.不合法,2.不合法,3.合法,4.合法,因为set的迭代器都是const,不可以对其修改
11.18:写出382页循环中map_it类型,不要使用auto或decltype
答:pair<const string,size_t>
11.19:定义一个变量,通过对378页中的名为bookstore的multiset调用begin()来初始化这个变量的类型,不要使用auto或者decltype
答:
#include<iostream>
#include<algorithm>
#include<map>
#include<unordered_map>
#include<set>
using namespace std;
unordered_map<string, vector<pair<string,int>>>mp;
class sale_data {
private:
int value;
public:
int get_value() {
return value;
}
};
typedef sale_data(*fd);
bool cmpareIsbn(sale_data a, sale_data b) {
return a.get_value() > b.get_value();
}
typedef bool(*pf)(sale_data a,sale_data b);
int main() {
sale_data a;
multiset<sale_data, pf>ans = { a };
auto iter = ans.begin();
multiset<sale_data, pf>::iterator iter = ans.begin();
return 0;
}
11.3.2节练习
11.20:重写单词计数程序,使用insert代替下标操作。你认为哪个程序跟容易编写和阅读?解释原因
答
#include<iostream>
#include<algorithm>
#include<map>
#include<unordered_map>
using namespace std;
unordered_map<string, int>mp;
int main() {
string str;
while (cin >> str) {
for (int i = 0;i < str.size();i++) {
if (str[i] >= 'A' && str[i] <= 'Z') {
str[i] += 32;
}
if (iswpunct(str[i])) {
str.erase(str.begin() + i);
}
}
auto iter = mp.insert({ str,1 });
if (!iter.second) {
iter.first->second++;
}
}
for (auto num : mp) {
cout << num.first << " ";
cout << num.second << endl;
}
return 0;
}
11.21:假定word_count是一个string到size_t的map,word是一个string,解释下面循环的作用
while(cin>>word)
++word_count.insert({word,0}).first->second;
答:插入函数返回pair迭代器,也就是待插入元素,在word中找是否有相同键值的元素,如果有,就让其关键字对应的值加一
11.22:给定一个map<string,vector< int >>,对此容器的插入一个元素的insert版本,写出其参数版本类型和返回类型
答:参数类型是string,int类型,返回类型是其迭代器
11.23:378页中的map以孩子的姓为关键字,保存他们的名的vector,用multimap重写map
答:
#include<iostream>
#include<algorithm>
#include<map>
#include<unordered_map>
using namespace std;
unordered_multimap<string, vector<pair<string, int>>>mp;
void add_family(string name, vector<pair<string, int>>son) {
mp.insert(make_pair(name, son));
}
void add_son(string family, string son_name, int age) {
vector<pair<string, int>>temp = { {son_name,age} };
mp.insert(make_pair(family,temp));
}
int main() {
string str;
vector<pair<string, int>>child = { make_pair("name",17) };
add_family("mr", child);
add_son("mr", "hello", 34);
add_son("mr", "int", 78);
for (auto num : mp) {
cout << num.first << " ";
for (auto curr : num.second) {
cout << curr.first << " " << curr.second << " ";
}
}
return 0;
}
11.3.4节练习
11.24:下面的程序完成什么功能?
map<int,int>m;
m[0]=1;
答:哈希表利用下标加入元素
11.25:对比下面程序与上一题程序
vector<int>v;
v[0]=1;
答:这段代码没有初始化,也没有分配内存,所以是错的,而map,由于其特性,利用下标会自动初始化
11.26:可以用什么类型来对一个map进行下标操作,下标运算符返回的类型是什么?请给出一个具体例子,定义一个map,然后写出一个可以用来对map进行下标操作的类型以及下标运算符将会返回的类型。
答:map键值的类型,返回类型是mapped_type对象
13.3.5节练习
11.27:对于什么问题你会使用count来解决?什么时候你又会选择find
答:要计数一般选择count,只是寻找则是find
11.28:对于一个string到int的vector的map,定义并初始化一个变量来保存在其上调用find的结果
答:
#include<iostream>
#include<algorithm>
#include<map>
#include<unordered_map>
using namespace std;
int main() {
map<string, vector<int>>mp = { {"hello",{1,2,3}} };
auto ans = mp.find("hello");
if (ans != mp.end())cout << ans->first << " ";
return 0;
}
11.29:如果给定的关键字不在容器中,upper_bound、lower_bound和equal_range会返回什么
答:指向关键字可以插入的地方
11.30:对于本节最后一个程序中的输出表达式,解释运算对象pos.first->second的含义
答:表示指向第一个查找到的关键字对应的元素的值
11.31:编写程序,定义一个作者及其作品的multimap。使用find在multimap中查找一个元素并用erase删除它。确保你的程序在元素不在map也能运行。
答:
#include<iostream>
#include<algorithm>
#include<map>
#include<unordered_map>
using namespace std;
int main() {
map<string, vector<int>>mp = { {"hello",{1,2,3}} };
multimap<string, vector<string>>mp1;
vector<string>temp = { "hello"};
vector<string>temp1 = { "return" };
mp1.insert(make_pair("hello", temp));
mp1.insert(make_pair("hello", temp1));
auto ans = mp1.find("hello");
if (ans != mp1.end()) {
for (auto num : ans->second)cout << num << " ";
mp1.erase(ans->first);
}
return 0;
}
11.32:使用上一题定义的multimap编写一个程序,按字典序打印作者列表和他们的作品
答:
#include<iostream>
#include<algorithm>
#include<map>
#include<unordered_map>
#include<set>
using namespace std;
int main() {
multimap<string, vector<string>>mp1;
vector<string>temp = { "b","a"};
vector<string>temp1 = { "b","a" };
mp1.insert(make_pair("li lei", temp));
mp1.insert(make_pair("wang mei", temp1));
multiset<string>my_set;
for (auto num : mp1) {
my_set.insert(num.first);
}
for (auto num : my_set) {
auto temp = mp1.find(num)->second;
sort(temp.begin(), temp.end());
cout << num << endl;
for (auto num : temp)cout << num << " ";
cout << endl;
}
return 0;
}
11.3.6节练习
11.33:实现你自己版本的单词转换程序
答:
map<string, string>buildMap(ifstream& map_file) {
map<string, string>trans_map;
string key;
string value;
while (map_file>>key && getline(map_file, value)) {
if (value.size() > 1)
trans_map[key] = value.substr(1);
else
throw runtime_error("no rules for" + key);
}
return trans_map;
}
const string& transform(const string& s, const map<string, string>& m) {
auto map_it = m.find(s);
if (map_it != m.end())return map_it->second;
else return s;
}
void word_transform(ifstream& map_file, ifstream& input) {
auto trans_map = buildMap(map_file);
string text;
while (getline(input, text)) {
istringstream stream(text);
string word;
bool firstword = true;
while (stream >> word) {
if (firstword)firstword = false;
else cout << " ";
cout << transform(word,trans_map);
}
cout << endl;
}
}
11.34:如果你将transform函数中的find替换为下标运算符,会发生什么
答:会发生意外,即便没有,下标也会直接初始化一个元素
11.35:在buildMap中,如果进行以下改写,会有什么效果
trans_map[key]=value.substr(1);
改为trans_map.insert({key,value.substr(1)});
答:``效果是一样的,但是无法覆盖新的内容
11.36:我们的程序并没有检查文件的合法性,特别是,它假定转换规则文件中的规则都是有意义的。如果文件中的某一行包含一个关键字,一个空格,然后就结束了,会发生什么。预测程序的行为并进行验证,再与你的程序进行比较。
答:会抛出错误
11.4节练习
11.37:一个无序容器与其版本相比有何优势?有序版本有何优势?
答:无序的效率通常更快,而有序则适用于需要排序的
11.38:用unordered_map重写单词计数程序和单词转换程序
答:将写过的单词计数和单词转换程序用unordered_map代替即可