Skip to content

Commit

Permalink
Add solutions to all exercises in chapter 11.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jaege committed Jan 24, 2016
1 parent cc2d8c6 commit 39cf43f
Show file tree
Hide file tree
Showing 45 changed files with 754 additions and 15 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,16 @@ This repo is the solutions to exercises in book [_C++ Primer_ (5th Edition)](htt
[31](ch10/10.31.cpp)|[32](ch10/10.32.cpp)|[33](ch10/10.33.cpp)|[34](ch10/10.34.cpp)|[35](ch10/10.35.cpp)|[36](ch10/10.36.cpp)|[37](ch10/10.37.cpp)|[38](ch10/10.38.md)|[39](ch10/10.39.md)|[40](ch10/10.40.md)|
[41](ch10/10.41.md)|[42](ch10/10.42.cpp)

<!---
#### Chapter 11 [](ch11)
#### Chapter 11 [Associative Containers](ch11)

1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
--:|--:|--:|--:|--:|--:|--:|--:|--:|--:
[1](ch11/11.1.cpp)|[2](ch11/11.2.cpp)|[3](ch11/11.3.cpp)|[4](ch11/11.4.cpp)|[5](ch11/11.5.cpp)|[6](ch11/11.6.cpp)|[7](ch11/11.7.cpp)|[8](ch11/11.8.cpp)|[9](ch11/11.9.cpp)|[10](ch11/11.10.cpp)|
[11](ch11/11.11.cpp)|[12](ch11/11.12.cpp)|[13](ch11/11.13.cpp)|[14](ch11/11.14.cpp)|[15](ch11/11.15.cpp)|[16](ch11/11.16.cpp)|[17](ch11/11.17.cpp)|[18](ch11/11.18.cpp)|[19](ch11/11.19.cpp)|[20](ch11/11.20.cpp)|
[21](ch11/11.21.cpp)|[22](ch11/11.22.cpp)|[23](ch11/11.23.cpp)|[24](ch11/11.24.cpp)|[25](ch11/11.25.cpp)|[26](ch11/11.26.cpp)|[27](ch11/11.27.cpp)|[28](ch11/11.28.cpp)|[29](ch11/11.29.cpp)|[30](ch11/11.30.cpp)|
[31](ch11/11.31.cpp)|[32](ch11/11.32.cpp)|[33](ch11/11.33.cpp)|[34](ch11/11.34.cpp)|[35](ch11/11.35.cpp)|[36](ch11/11.36.cpp)|[37](ch11/11.37.cpp)|[38](ch11/11.38.cpp)
[1](ch11/11.1.md)|[2](ch11/11.2.md)|[3](ch11/11.3.cpp)|[4](ch11/11.4.cpp)|[5](ch11/11.5.md)|[6](ch11/11.6.md)|[7](ch11/11.7.cpp)|[8](ch11/11.8.cpp)|[9](ch11/11.9.cpp)|[10](ch11/11.10.md)|
[11](ch11/11.11.md)|[12](ch11/11.12.cpp)|[13](ch11/11.13.md)|[14](ch11/11.14.cpp)|[15](ch11/11.15.md)|[16](ch11/11.16.cpp)|[17](ch11/11.17.md)|[18](ch11/11.18.md)|[19](ch11/11.19.md)|[20](ch11/11.20.cpp)|
[21](ch11/11.21.md)|[22](ch11/11.22.md)|[23](ch11/11.23.cpp)|[24](ch11/11.24.md)|[25](ch11/11.25.md)|[26](ch11/11.26.md)|[27](ch11/11.27.md)|[28](ch11/11.28.md)|[29](ch11/11.29.md)|[30](ch11/11.30.md)|
[31](ch11/11.31.cpp)|[32](ch11/11.32.md)|[33](ch11/11.33.cpp)|[34](ch11/11.34.md)|[35](ch11/11.35.md)|[36](ch11/11.36.md)|[37](ch11/11.37.md)|[38.1](ch11/11.38.1.cpp) [38.2](ch11/11.38.2.cpp)

<!---
#### Chapter 12 [](ch12)
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
Expand Down
16 changes: 7 additions & 9 deletions ch10/10.38.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ random-access iterator | bidirectional iterator operations `<` `<=` `>` `>=`

Iterator Hierarchy

input iterator output iterator
| |
+---------+----------+
|
forward iterator
|
bidirectional iterator
|
random-access iterator
input iterator output iterator
|
forward iterator
|
bidirectional iterator
|
random-access iterator
5 changes: 5 additions & 0 deletions ch11/11.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
A `map` is an associative container which contains an associative array of key-value pairs. Values are found by key. The key doesn't have to be integer.

A `vector` is an sequential container which contains a normal array of values. Values are found by position. The position is integer.


2 changes: 2 additions & 0 deletions ch11/11.10.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
We can define `map<vector<int>::iterator, int>` because the iterator of vector supports iterator arithmetic which includes `<` operator.
But we cannot define `map<list<int>::iterator, int>` because the iterator of list does not support iterator arithmetic and does not support `<` operator.
3 changes: 3 additions & 0 deletions ch11/11.11.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

multiset<Sales_data, bool (*)(const Sales_data &, const Sales_data &)>

20 changes: 20 additions & 0 deletions ch11/11.12.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include <string>
#include <utility>
#include <vector>
#include <iostream>

int main() {
std::vector<std::pair<std::string, int>> vp;
std::string s;
int i;
while (std::cin >> s >> i)
vp.push_back({s, i});
//vp.push_back(std::make_pair(s, i));
//vp.push_back(std::pair<std::string, int>(s, i));
// I think the braced inititalizer is the most easy way.

for (const auto &p : vp)
std::cout << p.first << " : " << p.second << std::endl;

return 0;
}
1 change: 1 addition & 0 deletions ch11/11.13.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
See [ex11.12](11.12.cpp).
48 changes: 48 additions & 0 deletions ch11/11.14.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include <string>
#include <map>
#include <vector>
#include <utility>
#include <iostream>

typedef std::map<std::string,
std::vector<std::pair<std::string, std::string>>> family_type;

void addFamily(family_type &families, const std::string &name) {
auto ret = families.insert({name,
std::vector<std::pair<std::string, std::string>>()});
if (!ret.second)
std::cerr << "Error: Already has family <" << name << ">" << std::endl;
}

void addChild(family_type &families, const std::string &family_name,
const std::string &child_name, const std::string &birthday) {
auto it = families.find(family_name);
if (it != families.end())
it->second.push_back({child_name, birthday});
else
std::cerr << "Error: No family <" << family_name << "> for child <"
<< child_name << "> born on " << birthday << std::endl;
}

int main() {
family_type families;
addFamily(families, "Zhang");
addFamily(families, "Li");
addFamily(families, "Wang");
addFamily(families, "Zhang"); // Error

addChild(families, "Zhang", "San", "1990-1-1");
addChild(families, "Zhang", "Bao", "1990-1-2");
addChild(families, "Zhang", "Tian", "1990-1-3");
addChild(families, "Li", "Si", "1990-1-4");
addChild(families, "Wang", "Wu", "1990-1-5");
addChild(families, "Wang", "San", "1990-1-6");
addChild(families, "Zhao", "Liu", "1990-1-7"); // Error

for (const auto &family : families)
for (const auto &child : family.second)
std::cout << family.first << " " << child.first << " "
<< child.second << std::endl;

return 0;
}
5 changes: 5 additions & 0 deletions ch11/11.15.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
For `map<int, vector<int>>`:

- `mapped_type` is `vector<int>`.
- `key_type` is `int`.
- `value_type` is `pair<int, vector<int>>`.
18 changes: 18 additions & 0 deletions ch11/11.16.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include <map>
#include <iostream>

int main() {
std::map<int, int> mi;
int a, b;
while (std::cin >> a >> b) {
auto it = mi.find(a);
if (it != mi.end())
it->second = b;
else
mi.insert({a, b});
}
for (auto it = mi.cbegin(); it != mi.cend(); ++it)
std::cout << it->first << " : " << it->second << std::endl;

return 0;
}
17 changes: 17 additions & 0 deletions ch11/11.17.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Assume `multiset<string> c; vector<string> v;`, then

copy(v.begin(), v.end(), inserter(c, c.end()));

is OK.

copy(v.begin(), v.end(), back_inserter(c));

is error. A `multiset` doesn't have `push_back` memeber function.

copy(c.begin(), c.end(), inserter(v, v.end()));

is OK.

copy(c.begin(), c.end(), back_inserter(v));

is OK.
4 changes: 4 additions & 0 deletions ch11/11.18.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
The type is

map<string, size_t>::const_iterator

5 changes: 5 additions & 0 deletions ch11/11.19.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
The definition can be written as

multiset<Sales_data, bool (*)(const Sales_data &, const Sales_data &>::iterator it = bookstore.begin();

Note that iterators for `set`s are always `const`.
9 changes: 9 additions & 0 deletions ch11/11.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
A `list` may be used when we need to insert/delete at the middle frequently, such as a linked list.

A `vector` may be used when we need random-access, such as a dynamic normal array.

A `deque` may be used like a queue.

A `map` may be used like a dictionary.

A `set` may be used to check whether a value is present.
51 changes: 51 additions & 0 deletions ch11/11.20.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include <map>
#include <set>
#include <vector>
#include <string>
#include <iterator>
#include <iostream>
#include <fstream>

std::string trimStr(std::string s) {
constexpr char *punctuations{"\"'`:*-_;,.?!()[]{}"};
for (auto &c : s)
if (c >= 'A' && c <= 'Z') c -= 'A' - 'a';
size_t bg = s.find_first_not_of(punctuations);
if (bg == std::string::npos)
return "";
size_t ed = s.find_last_not_of(punctuations);
return s.substr(bg, ed - bg + 1);
}

std::map<std::string, size_t> count_words(std::vector<std::string> &words) {
std::map<std::string, size_t> counts;
for (const auto &w : words) {
//++counts[trimStr(w)];
auto ret = counts.insert({trimStr(w), 1});
if (!ret.second)
++ret.first->second;
// The subscirpt way is easier to write, but hard to notice the fact that
// it will add element if not existed.
}
return counts;
}

int main() {
std::string filename;
std::cin >> filename;
std::ifstream in(filename);
if (!in.is_open()) {
std::cerr << "Cannot open file: " << filename << std::endl;
return -1;
}
std::istream_iterator<std::string> i_iter(in), eof;
std::vector<std::string> words(i_iter, eof);
for (const auto &w : words)
std::cout << w << std::endl;
auto counts = count_words(words);
for (const auto &w: counts)
std::cout << "\"" << w.first << "\" occurs " << w.second
<< (w.second > 1 ? " times." : " time.") << std::endl;

return 0;
}
4 changes: 4 additions & 0 deletions ch11/11.21.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
while (cin >> word)
++word_count.insert({word, 0}).first->second;

The code just does the same thing as `++word_count[word];`. If the `word` is in `map`, then increase the count of that word by 1, else insert that word into `map`, set the count to 0, and increase the count by 1.
1 change: 1 addition & 0 deletions ch11/11.22.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The return type is `pair<map<string, vector<int>>::iterator, bool>`.
53 changes: 53 additions & 0 deletions ch11/11.23.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include <string>
#include <map>
#include <vector>
#include <iostream>

typedef std::multimap<std::string, std::vector<std::string>> family_type;

void addFamily(family_type &families, const std::string &name) {
families.insert({name, std::vector<std::string>()}); // always insert value
//auto ret = families.insert({name, std::vector<std::string>()});
//if (!ret.second)
// std::cerr << "Error: Already has family <" << name << ">" << std::endl;
}

void addChild(family_type &families, const std::string &family_name,
const std::string &child_name) {
auto it = families.find(family_name);
if (it != families.end())
it->second.push_back(child_name);
else
std::cerr << "Error: No family <" << family_name << "> for child <"
<< child_name << ">" << std::endl;
}

int main() {
family_type families;
addFamily(families, "Zhang");
addFamily(families, "Li");
addFamily(families, "Wang");

addChild(families, "Zhang", "San");
addChild(families, "Zhang", "Bao");
addChild(families, "Zhang", "Tian");
addChild(families, "Li", "Si");
addChild(families, "Wang", "Wu");
addChild(families, "Wang", "San");
addChild(families, "Zhao", "Liu"); // Error

addFamily(families, "Zhang");
// OK, but the following two statement will add to the first "Zhang" key,
// because we use `find()` to find the first present key.
addChild(families, "Zhang", "Mei");
addChild(families, "Zhang", "Lu");

for (const auto &family : families) {
std::cout << family.first << "'s family:" << std::endl;
for (const auto &name : family.second)
std::cout << family.first << " " << name << std::endl;
std::cout << std::endl;
}

return 0;
}
1 change: 1 addition & 0 deletions ch11/11.24.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The code adds a new key `0` to the map `m` and value initializes its value to 0, then assigns 1 to its value.
1 change: 1 addition & 0 deletions ch11/11.25.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The code will cause error. Because the subscript operator accesses element that not existed, the behaviour is undefined.
6 changes: 6 additions & 0 deletions ch11/11.26.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
A type which can be used as a `key_type` can be used to subscript a `map`. The subscript operator return `mapped_type`. For example:

map<string, int> world_counts;
string str("Hello");
int cnt = world_counts[str];

1 change: 1 addition & 0 deletions ch11/11.27.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
We can use `count` if the key is present multiple times and we want to know how many. We can use `find` if we only want to know whether the key is present.
2 changes: 2 additions & 0 deletions ch11/11.28.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
map<string, vector<int>> mp;
map<string, vector<int>>::iterator it = mp.find("some key");
5 changes: 5 additions & 0 deletions ch11/11.29.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
When we pass a key that is not in container,

- `upper_bound` will return `c.end()`,
- `lower_bound` will return `c.end()`,
- `equal_range` will return `make_pair(c.end(), c.end())`.
32 changes: 32 additions & 0 deletions ch11/11.3.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include <map>
#include <set>
#include <vector>
#include <string>
#include <iterator>
#include <iostream>
#include <fstream>

std::map<std::string, size_t> count_words(std::vector<std::string> &words) {
std::map<std::string, size_t> counts;
for (const auto &w : words)
++counts[w];
return counts;
}

int main() {
std::string filename;
std::cin >> filename;
std::ifstream in(filename);
if (!in.is_open()) {
std::cerr << "Cannot open file: " << filename << std::endl;
return -1;
}
std::istream_iterator<std::string> i_iter(in), eof;
std::vector<std::string> words(i_iter, eof);
auto counts = count_words(words);
for (const auto &w: counts)
std::cout << w.first << " occurs " << w.second
<< (w.second > 1 ? " times." : " time.") << std::endl;

return 0;
}
5 changes: 5 additions & 0 deletions ch11/11.30.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
`pos` is a pair of iterators.

`pos.first` is the first iterator in pair.

`pos.first->second` derefences the iterator and get a pair of two strings, then returns the second string.
Loading

0 comments on commit 39cf43f

Please sign in to comment.