本书为Primer C++ 中文第五版
练习题笔记
(11.1)
map是关键字-值对的集合。vector是值的集合。
map是关联容器,高效实现“按值访问元素”。容器里的元素是按关键字值存储的,关键字和元素数据建立对应关系。底层数据结构是红黑树,哈希表等,可高效地实现按关键字查找、添加、删除等操作。
vector是顺序容器,元素是按顺序存储。操作是按位置进行的。
(11.2)
vector 适用于顺序的添加,非大量频繁的删除操作
list 适用于大量的删除操作
deque 适用于两头添加的操作
set 适用于判断是否存在的操作
map 适用于键值对的操作
(11.3)
void test3() {
map<string, size_t> word_count;
set<string> exclude = {"The", "But", "And", "Or", "An", "A",
"the", "but", "and", "or", "an", "a"};
string word;
while(cin >> word && word != "q") {
//find 返回一个迭代器,如果存在返回关键字,否则返回尾后迭代器
if(exclude.find(word) == exclude.end())
//map类型以关键字为下标,获得其对应的值
++word_count[word];
}
for(const auto &w : word_count) {
cout << w.first << " occurs " << w.second
<< ((w.second > 1)? " times " : " time ") << endl;
}
}
(11.4)
void test4() {
map<string, size_t> word_count;
set<string> exclude = {"The", "But", "And", "Or", "An", "A",
"the", "but", "and", "or", "an", "a"};
string word;
while(cin >> word && word != "q") {
int len = word.size() - 1;
if(word[len] == ',' || word[len] == '.' || word[len] == '!' || word[len] == '?') {
word = word.substr(0, len);
}
transform(word.begin(), word.end(), word.begin(), ::tolower);
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;
}
}
(11.5)
map 用来键值对的操作
set 用来判断某个值是否存在
(11.6)
set 可以快速的判断某个值是否存在
list 则是按位置或者顺序对里面的值进行访问操作
(11.7)
void test7() {
map<string, vector<string>> home;
set<string> firstname;
string s,e;
while(cin >> s >> e && s != "q") {
if(firstname.find(s) == firstname.end()) {
firstname.insert(s);
cout << "creat a new home" << endl;
home[s].push_back(e);
}else {
cout << "home have exited" << endl;
home[s].push_back(e);
}
}
for(auto iter = home.begin(); iter != home.end(); ++iter) {
cout << iter->first << " ";
for(auto scan = iter->second.begin(); scan < iter->second.end(); ++scan) {
cout << *scan << " ";
}
cout << endl;
}
}
(11.8)
/**
*使用vector中的find函数需要加上头文件#include <algorithm>;
*而且比较繁琐
*/
void test8() {
vector<string> exclude = {"The", "But", "And", "Or", "An", "A",
"the", "but", "and", "or", "an", "a"};
string s;
while(cin >> s && s != "q") {
auto iter = find(exclude.begin(), exclude.end(), s);
if(iter == exclude.end()) cout << "not exits" << endl;
else cout << "exits" << endl;
}
}
(11.9)
void test9() {
map<string, list<int>> strlst;
ifstream fin("test.txt");
int l = 1;
while(!fin.eof()) {
string line;
getline(fin, line);
stringstream input(line);
string word;
while(input >> word) {
cout << word << " ";
if(strlst.find(word) == strlst.end()) {
list<int> def;
def.push_back(l);
strlst[word] = def;
}else {
auto lst = strlst[word];
auto findif = find(lst.begin(), lst.end(), l);
if(findif == lst.end()) {
strlst[word].push_back(l);
}
}
}
cout << endl;
l++;
}
for(auto scan = strlst.begin(); scan != strlst.end(); ++scan) {
cout << scan->first << "\t";
for(auto lst = scan->second.begin(); lst != scan->second.end(); ++lst) {
cout << *lst << "\t";
}
cout << "\n";
}
}
(11.10)
关联容器对关键字类型有一些限制。对于有序容器map,multimap,set,multiset,关键字类型必须定义元素比较的方法。
(11.11)
回顾:
decltype((variable))的结果永远是引用
而decltype(variable)只有当variable本身就是一个引用时,才是引用,引用必须被初始化
decltype(f()) sum = x; //sum的类型就是函数f的返回类型
typedef a b; 给a取个别名为b
可以利用类型别名,
typedef bool (*pf)(const Sales_data &lhs, const Sales_data &rhs);
multiset<Sales_data, pf> bookstore(compareIsbn);
(11.12)
void test12() {
vector<pair<string, int>> res;
string s;
int n = 0;
while(cin >>s && s != "q") {
pair<string, int> p = {s, n};
res.push_back(p);
n++;
}
for(auto p : res) {
cout << p.first << " " << p.second << endl;
}
}
(11.13)
void test13() {
vector<pair<string, int>> res;
vector<pair<string, int>> res1;
vector<pair<string, int>> res2;
string s;
int n = 0;
while(cin >>s && s != "q") {
pair<string, int> p = {s, n};
pair<string, int> p1(s, n);
res.push_back(p);
res1.push_back(make_pair(s, n));
res2.push_back(p1);
n++;
}
for(auto p : res) {
cout << p.first << " " << p.second << endl;
}
for(auto p : res1) {
cout << p.first << " " << p.second << endl;
}
for(auto p : res2) {
cout << p.first << " " << p.second << endl;
}
}
//个人更喜欢使用make_pair()
(11.14)
void test14() {
map<string, pair<string, string>> people;
string fn, la, bir;
while(cin >> fn >> la >> bir && fn != "q") {
people[fn] = make_pair(la, bir);
}
for(auto p : people) {
cout << p.first << p.second.first << p.second.second << endl;
}
}
(11.15)
map<int, vector<int>> test;
key_type : int
mapped_type : vector<int>
value_type : pair<const int, vector<int>>
(11.16)
void test16() {
map<string, int> m;
int n = 0;
string s = "a";
for(int i = 0; i < 5; ++i) {
m[s] = i;
s = s.append(s);
}
for(auto sc = m.begin(); sc != m.end(); ++sc) {
cout << sc->first << " " << sc->second << endl;
}
}
(11.17)
因为set的迭代器是const的,只允许访问元素
所以前两个非法,后面两个合法
(11.18)
map<const string, size_t>::iterator
(11.19)
multiset<Sales_data, pf>::iterator iter = bookstore.begin();
(11.20)
void test20() {
map<string, size_t> word_count;
string word;
while(cin >> word && word != "q") {
auto ret = word_count.insert({word, 1});
//insert插入成功res.second为true,ret.first指向word_count[word]的迭代器
if(!ret.second) ret.first->second++;
// ++word_count.insert({word, 0}).first->second;
}
for(const auto &w : word_count) {
cout << w.first << " occurs " << w.second
<< ((w.second > 1)? " times " : " time ") << endl;
}
}
(11.21)
首先是在map word_count插入值
然后 word_count.insert({word,0}).first 是指向word_count[word]的迭代器
最后将word_count[word]值增加1
等价于上一题的写法
(11.22)
参数类型: pair<string, vector<int>>
返回类型: pair<map<string, vector<int>>::iterator, bool>
(11.23)
void test23() {
multimap<string, string> home;
string fn, la;
while(cin >> fn >> la && fn != "q") {
home.insert({fn, la});
}
for(auto iter = home.begin(); iter != home.end(); ++iter) {
cout << iter->first << " " << iter->second << endl;
}
}
(11.24)
先创建一个关键字为0,值为0的pair类元素。然后将该关键字的对应的值赋值为1。
(11.25)
v是一个空的容器,用下标访问它的非法位置0的元素会引发错误造成系统崩溃。
(11.26)
对map进行下标操作的类型是该map的key_type
下标运算符返回的类型是该map的mapped_type
eg.map<string, int> msi;可以利用string类型的对msi进行下标操作,返回的类型为int类型
(11.27)
只关心一个特定元素是否已在容器中,find是最佳选择。
对于不允许重复关键字的容器find和count作用是一样的。
对于允许重复关键字的容器,count会统计有多少个元素相同的关键字。
(11.28)
void test28() {
map<string, vector<int>> msv;
string s = "a";
vector<int> vi;
for(int i = 0; i < 5; ++i) {
vi.push_back(i);
msv.insert({s, vi});
s = s.append(s);
}
for(auto i : msv.find("aaaa")->second) {
cout << i << " ";
}
cout << endl;
}
(11.29)
接受一个关键字,返回一个迭代器
lower_bound();指向第一个具有给定关键字的元素
upper_bound();指向最后一个匹配给定关键字的元素之后的位置
若元素不存在,返回一个相等的迭代器,指向一个不影响排序的关键字插入位置。
接受一个关键字,返回一个迭代器pair
equal_range();若存在,第一个迭代器指向第一个与关键字匹配的元素,第二个迭代器指向最后一个匹配元素之后的位置。若未找到匹配元素,则两个迭代器都指向关键字可以插入的位置。
(11.30)
pos.first代表与关键字匹配元素的迭代器
pos.first->second代表该关键字指向的值
(11.31)
(11.32)
void test3132() {
multimap<string, string> books;
books.insert({"JY", "TLBB"});
books.insert({"YG", "BLSMY"});
books.insert({"YG", "BCSJ"});
books.insert({"LLXXS", "JPM"});
cout << "origin:" << endl;
for(auto b : books) {
cout << b.first << " " << b.second << endl;
}
cout << "delete:" << endl;
for(auto pos = books.equal_range("JY"); pos.first != pos.second; ++pos.first) {
cout << pos.first->first << " " << pos.first->second << endl;
books.erase(pos.first->first);
}
cout << "end:" << endl;
for(auto begin = books.begin(); begin != books.end(); ++begin) {
cout << begin->first << " " << begin->second << endl;
}
}
(11.33)
#include <iostream>
#include <map>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;
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 rule for key: " + 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 << " ";
if(word[word.size()-1] == ',' || word[word.size()-1] == '.' || word[word.size()-1] == '?' || word[word.size()-1] == '!') word = word.substr(0, word.size() - 1);
cout << transform(word, trans_map);
}
cout << endl;
}
}
void test33() {
ifstream fmap("map.txt");
ifstream finput("input.txt");
word_transform(fmap, finput);
}
int main() {
test33();
return 0;
}
(11.34)
会使得本来不存在转换的值,经过下标操作创建该值存到map中
(11.35)
当key不存在的时候,这两种情况都会是创建
但是当key已经存在的时候,第一种情况是替换key的value,而第二种则是什么也不会做
(11.36)
例子中已经进行了判断,如果没有对应的value,则会抛出runtime_error
(11.37)
无序容器不需要维护元素的排序,在性能测试和调优工作有着很好的效果。如果不是必须对关键字排序,用无序容器有着更好的性能。
(11.38)
略略略了,只需要把map改成unordered_mao即可