第十一章 关联容器
11.1
map是关键字-值对的集合,通过关键字来查找值。
vector是对象的集合,每个对象都有一个关联的索引,它提供对该对象的访问。
11.2
list:需要在任何地方插入或删除元素。
vector:保存一些重要的关联数据,总是需要按索引查询元素。
deque:先进先出。
map:字典。
set:错误的检查。(关键字的简单集合)
11.3~11.4
函数remove_if()移除序列[start, end)中所有应用于谓词p返回true的元素.
此函数返回一个指向被修剪的序列的最后一个元素迭代器.
记住, remove_if()并不会实际移除序列[start, end)中的元素; 如果在一个容器上应用remove_if(), 容器的长度并不会改变(remove_if()不可能仅通过迭代器改变容器的属性), 所有的元素都还在容器里面. 实际做法是, remove_if()将所有应该移除的元素都移动到了容器尾部并返回一个分界的迭代器. 移除的所有元素仍然可以通过返回的迭代器访问到. 为了实际移除元素, 你必须对容器自行调用erase()以擦除需要移除的元素. 这也是erase-remove idiom名称的由来.
#include <iostream>
#include <map>
#include <string>
#include <algorithm>
#include <cctype>
//! Exercise 11.4
void word_count_pro(std::map<std::string, int>& m)
{
std::string word;
while (std::cin >> word) {
for (auto& ch : word) ch = tolower(ch);
//! According to the erase-remove idiom.
//! For more information about the erase-remove idiom, please refer to
//! http://en.wikipedia.org/wiki/Erase-remove_idiom
word.erase(std::remove_if(word.begin(), word.end(), ispunct),
word.end());
++m[word];
}
for (const auto& e : m) std::cout << e.first << " : " << e.second << "\n";
}
//! Exercise 11.3
void ex11_3()
{
std::map<std::string, std::size_t> word_count;
std::string word;
while (std::cin >> word) ++word_count[word];
for (const auto& elem : word_count)
std::cout << elem.first << " : " << elem.second << "\n";
}
int main()
{
std::map<std::string, int> m;
word_count_pro(m);
return 0;
}
11.5
set:元素类型是关键字类型
map:使用关键字_值对。
11.6
set中元素是唯一的和有序的,但list都不是。
11.7
#include <iostream>
#include <map>
#include <string>
#include <algorithm>
int main()
{
std::map<std::string, std::vector<std::string>> famls;
std::string lastName, chldName;
//! while(lambda)
//! go to the discussions on stack overfow for more.
while ([&]() -> bool {
std::cout << "Please enter last name:\n";
return std::cin >> lastName && lastName != "@q";
}())
//! ^^
//! the () used here is to call the lambda ,otherwise it does not work
//! go to the post on stack overflow for more detail.
{
std::cout << "PLZ Enter children's name:\n";
while (std::cin >> chldName && chldName != "@q") {
//! add new items into the vector
famls[lastName].push_back(chldName);
}
}
//! iterate through the map.
for (auto e : famls) {
std::cout << e.first << ":\n";
//! iterate through the vector.
for (auto c : e.second) std::cout << c << " ";
std::cout << "\n";
}
return 0;
}
11.8
使用set的好处:
添加删除元素将始终有序,但不允许添加重复的
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int main()
{
std::vector<std::string> exclude = {"aa", "bb", "cc"};
for (std::string word; std::cin >> word;) {
if (std::find(exclude.begin(), exclude.end(), word) != exclude.end())
std::cout << "excluded!" << std::endl;
else
exclude.push_back(word);
}
for (auto const& s : exclude) std::cout << s << " ";
std::cout << std::endl;
}
11.9~11.10
#include <iostream>
#include <map>
#include <string>
#include <algorithm>
#include <list>
int main()
{
//! ex 11.9
std::map<std::string, std::list<std::size_t>> m;
//! ex 11.10
//! can be declared.
std::map<std::vector<int>::iterator, int> mv;
std::map<std::list<int>::iterator, int> ml;
std::vector<int> vi;
mv.insert(std::pair<std::vector<int>::iterator, int>(vi.begin(), 0));
//! but when using this one the compiler complained that
//! error: no match for 'operator<' in '__x < __y'
std::list<int> li;
ml.insert(std::pair<std::list<int>::iterator, int>(li.begin(), 0));
return 0;
}
11.11
#include "../ch07/ex7_26_sales_data.h"
#include <set>
bool compareIsbn(const Sales_data& lhs, const Sales_data& rhs)
{
return lhs.isbn() < rhs.isbn();
}
int main()
{
using compareType = bool (*)(const Sales_data& lhs, const Sales_data& rhs);
// typedef bool(*compareType)(const Sales_data &lhs, const Sales_data &rhs);
std::multiset<Sales_data, compareType> bookstore(compareIsbn);
}
11.12~11.13
#include <vector>
#include <utility>
#include <string>
#include <iostream>
int main()
{
std::vector<std::pair<std::string, int>> vec;
std::string str;
int i;
while (std::cin >> str >> i)
vec.push_back(std::pair<std::string, int>(str, i));
// vec.push_back(std::make_pair(str, i));
// vec.push_back({str, i});
// vec.emplace_back(str, i); //!!! easiest way.
for (const auto& p : vec)
std::cout << p.first << ":" << p.second << std::endl;
}
11.14
#include <iostream>
#include <map>
#include <string>
#include <vector>
using std::ostream;
using std::cout;
using std::cin;
using std::endl;
using std::string;
using std::make_pair;
using std::pair;
using std::vector;
using std::map;
class Families {
public:
using Child = pair<string, string>;
using Children = vector<Child>;
using Data = map<string, Children>;
void add(string const& last_name, string const& first_name, string birthday)
{
_data[last_name].push_back(make_pair(first_name, birthday));
}
ostream& print(std::ostream& os) const
{
if (_data.empty()) return os << "No data right now." << endl;
for (const auto& pair : _data) {
os << pair.first << ":\n";
for (const auto& child : pair.second)
os << child.first << " " << child.second << endl;
os << endl;
}
return os;
}
private:
Data _data;
};
int main()
{
Families families;
string message = "Please enter last name, first name and birthday";
for (string l, f, b; cout << message << endl, cin >> l >> f >> b;
families.add(l, f, b))
;
families.print(cout << "Current data:" << endl);
return 0;
}
11.15
mapped_type:vector<int>
key_type:int
value_type:std::pair<const int, vector<int>>
11.16
std::map<int, std::string> map;
map[25] = "Alan";
std::map<int, std::string>::iterator it = map.begin();
it ->second = "Wang";
11.17
(a)合法,将v插入到c的尾部。
(b) 不合法,set中没有push_back
(c)合法。
(d)合法。
11.18
map<string, size_t>::const_iterator
11.19
using compareType = bool (*)(const Sale_data& lhs, const Sales_data & rhs);
std::multiset<Sales_data, compareType> bookstore(compareIsbn);
std::multiset<Sales_data,compareType>::iterator c_it = boolstore.begin();
11.20
#include <iostream>
#include <map>
#include <string>
using std::string;
int main()
{
std::map<string, size_t> word_count;
string word;
while (std::cin >> word) {
auto ret = word_count.insert({word, 1});
if (!ret.second) ++ret.first->second;
}
//! print the content of the map.
for (const auto& w : word_count)
std::cout << w.first << " " << w.second
<< ((w.second > 1) ? " times" : " time") << std::endl;
}
11.21
++word_count.insert({word,0}).first -> second;
11.22
std::pair<std::string, std::vector<int>> //argument
std::pair<std:mapa<std::string, std:vector<int>>::iterator, bool> //return
11.23
#include <map>
#include <string>
#include <iostream>
using std::string;
int main()
{
std::multimap<string, string> families;
for (string lastName, childName; std::cin >> childName >> lastName;
families.emplace(lastName, childName))
;
for (const auto& s : families)
std::cout << s.second << " " << s.first << std::endl;
}
11.24~11.26
#include <iostream>
#include <map>
#include <string>
#include <algorithm>
#include <vector>
int main()
{
//! ex11.24
std::map<int, int> m;
m[0] = 1;
for (const auto& e : m) std::cout << e.first << " " << e.second << "\n";
//! ex11.25
std::vector<int> v;
v[0] = 1;
for (const auto& e : v) std::cout << e << "\n";
//! ex11.26
std::map<int, std::string> map = {{1, "ss"}, {2, "sz"}};
std::map<int, std::string>::key_type type_to_subscript = 1;
//! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//! that is, int.
std::map<int, std::string>::mapped_type type_to_return =
map[type_to_subscript];
//! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//! that is, std::string
return 0;
}
11.27
使用count处理multimap和multiset;其他时候用find.
11.28
#include <iostream>
#include <map>
#include <string>
#include <algorithm>
#include <vector>
int main()
{
std::map<std::string, std::vector<int>> m;
m = {{"Alan",
{
1, 2, 3, 4, 5,
}},
{"John", {1, 5, 6, 7, 8}}};
//! ex11.28
std::map<std::string, std::vector<int>>::iterator it;
//! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//! type used to define this iterator.
it = m.find("Alan");
return 0;
}
11.29
前两个会返回相等的迭代器-指向一个不影响排序的关键字插入位置。
后一个会返回一个迭代器pair,其中两个迭代器都指向关键字可以插入的地方。
11.30
pos a pair
pos.first 是pair的第一个成员,是指向第一个与关键字匹配的元素的迭代器
pos.first -> second 解引用此迭代器,获取对象的second成员。
11.31
#include <iostream>
#include <map>
#include <string>
using std::string;
int main()
{
std::multimap<string, string> authors{
{"alan", "DMA"}, {"pezy", "LeetCode"}, {"alan", "CLRS"},
{"wang", "FTP"}, {"pezy", "CP5"}, {"wang", "CPP-Concurrency"},
{"pezy", "CP5"}};
// want to delete an element that author is [pezy], work is [CP5].
string author = "pezy";
string work = "CP5";
for (auto found = authors.find(author);
found != authors.end() && found->first == author;) {
if (found->second == work)
found = authors.erase(found);
else
++found;
}
for (const auto& author : authors)
std::cout << author.first << " " << author.second << std::endl;
}
11.32
#include <map>
#include <set>
#include <string>
#include <iostream>
using std::string;
int main()
{
std::multimap<string, string> authors{
{"alan", "DMA"}, {"pezy", "LeetCode"}, {"alan", "CLRS"},
{"wang", "FTP"}, {"pezy", "CP5"}, {"wang", "CPP-Concurrency"}};
std::map<string, std::multiset<string>> order_authors;
for (const auto& author : authors)
order_authors[author.first].insert(author.second);
for (const auto& author : order_authors) {
std::cout << author.first << ": ";
for (const auto& work : author.second) std::cout << work << " ";
std::cout << std::endl;
}
}
11.33
#include <map>
#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
using std::string;
using std::ifstream;
std::map<string, string> buildMap(ifstream& map_file)
{
std::map<string, string> trans_map;
for (string key, value; map_file >> key && getline(map_file, value);)
if (value.size() > 1)
trans_map[key] =
value.substr(1).substr(0, value.find_last_not_of(' '));
return trans_map;
}
const string& transform(const string& s, const std::map<string, string>& m)
{
auto map_it = m.find(s);
return map_it == m.cend() ? s : map_it->second;
}
void word_transform(ifstream& map, ifstream& input)
{
auto trans_map = buildMap(map);
for (string text; getline(input, text);) {
std::istringstream iss(text);
for (string word; iss >> word;)
std::cout << transform(word, trans_map) << " ";
std::cout << std::endl;
}
}
int main()
{
ifstream ifs_map("../data/word_transformation_bad.txt"),
ifs_content("../data/given_to_transform.txt");
if (ifs_map && ifs_content)
word_transform(ifs_map, ifs_content);
else
std::cerr << "can't find the documents." << std::endl;
}
11.34
如果关键字不在容器中,下标运算符会创建一个pair并进行值初始化。但m声明为对常量的引用,插入新值,会导致错误。
11.35
使用substr: 如果有一个单词出现多次,循环会将最后一个对应短语存入trans_map(重复复制)
使用insert: 如果有一个单词出现多次,循环会将最先一个对应短语存入trans_map(重复不插入)
11.36
11.33做了处理。
11.37
无序容器:在关键字类型的元素没有明显的序关系的情况下,无序容器是非常有用的。在某些应用中,维护元素的序代价非常高昂,此时无序容器也很有用。
有序容器:迭代器可以访问元素,还可以定义关键字类型为自定义类类型的容器,但是无序容器只能定义关键字是内置类型(包括指针类型),string,智能指针类型的无序容器。
11.38
#include <unordered_map>
#include <set>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
using std::string;
void wordCounting()
{
std::unordered_map<string, size_t> word_count;
for (string word; std::cin >> word; ++word_count[word])
;
for (const auto& w : word_count)
std::cout << w.first << " occurs " << w.second
<< (w.second > 1 ? "times" : "time") << std::endl;
}
void wordTransformation()
{
std::ifstream ifs_map("../data/word_transformation.txt"),
ifs_content("../data/given_to_transform.txt");
if (!ifs_map || !ifs_content) {
std::cerr << "can't find the documents." << std::endl;
return;
}
std::unordered_map<string, string> trans_map;
for (string key, value; ifs_map >> key && getline(ifs_map, value);)
if (value.size() > 1)
trans_map[key] =
value.substr(1).substr(0, value.find_last_not_of(' '));
for (string text, word; getline(ifs_content, text); std::cout << std::endl)
for (std::istringstream iss(text); iss >> word;) {
auto map_it = trans_map.find(word);
std::cout << (map_it == trans_map.cend() ? word : map_it->second)
<< " ";
}
}
int main()
{
// wordCounting();
wordTransformation();
}