第十章 泛型算法

练习10.1

头文件algorithm中定义了一个名为count的函数,它类似find, 接受一对迭代器和一个值作为参数。count返回给定值在序列中出现的次数。编写程序,读取int序列存入vector中,打印有多少个元素的值等于给定值。

解:

见下题

练习10.2

重做上一题,但读取 string 序列存入 list 中。

解:

  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <algorithm>
  5. #include <list>
  6. int main()
  7. {
  8. // 10.1
  9. std::vector<int> v = { 1, 2, 3, 4, 5, 6, 6, 6, 2 };
  10. std::cout << "ex 10.01: " << std::count(v.cbegin(), v.cend(), 6) << std::endl;
  11. // 10.2
  12. std::list<std::string> l = { "aa", "aaa", "aa", "cc" };
  13. std::cout << "ex 10.02: " << std::count(l.cbegin(), l.cend(), "aa") << std::endl;
  14. return 0;
  15. }

练习10.3

accumulate求一个 vector<int> 中元素之和。

解:

见下题。

练习10.4

假定 v 是一个vector<double>,那么调用 accumulate(v.cbegin(),v.cend(),0) 有何错误(如果存在的话)?

  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <algorithm>
  5. #include <numeric>
  6. int main()
  7. {
  8. // Exercise 10.3
  9. std::vector<int> v = { 1, 2, 3, 4 };
  10. std::cout << "ex 10.03: " << std::accumulate(v.cbegin(), v.cend(), 0) << std::endl;
  11. // Exercise 10.4
  12. std::vector<double> vd = { 1.1, 0.5, 3.3 };
  13. std::cout << "ex 10.04: "
  14. << std::accumulate(vd.cbegin(), vd.cend(), 0)
  15. << std::endl; // ^<-- note here.
  16. // @attention
  17. //
  18. // The ouput is 4 rather than 4.9 as expected.
  19. // The reason is std::accumulate is a template function. The third parameter is _Tp __init
  20. // When "0" , an integer, had been specified here, the compiler deduced _Tp as
  21. // interger.As a result , when the following statments were being excuted :
  22. // for (; __first != __last; ++__first)
  23. // __init = __init + *__first;
  24. // return __init;
  25. // all calculation would be converted to integer.
  26. return 0;
  27. }

结果会是 int 类型。

练习10.5

在本节对名册(roster)调用equal的例子中,如果两个名册中保存的都是C风格字符串而不是string,会发生什么?

C风格字符串是用指向字符的指针表示的,因此会比较两个指针的值(地址),而不会比较这两个字符串的内容。

练习10.6

编写程序,使用 fill_n 将一个序列中的 int 值都设置为0。

解:

  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. using std::vector; using std::cout; using std::endl; using std::fill_n;
  5. int main()
  6. {
  7. vector<int> vec{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  8. fill_n(vec.begin(), vec.size(), 0);
  9. for (auto i : vec)
  10. cout << i << " ";
  11. cout << endl;
  12. }

练习10.7

下面程序是否有错误?如果有,请改正:

  1. (a) vector<int> vec; list<int> lst; int i;
  2. while (cin >> i)
  3. lst.push_back(i);
  4. copy(lst.cbegin(), lst.cend(), vec.begin());
  5. (b) vector<int> vec;
  6. vec.reserve(10);
  7. fill_n(vec.begin(), 10, 0);

解:

  • (a) 应该加一条语句 vec.resize(lst.size())copy时必须保证目标目的序列至少要包含与输入序列一样多的元素。
  • (b) reserve分配了足够的空间,但是不会创建新元素。算法可能改变容器中保存的元素的值,也可能在容器内移动元素,永远不会直接添加和删除元素(c++ priemr中文版第五版 P338),所以此处应该改为resize(10)。

练习10.8

本节提到过,标准库算法不会改变它们所操作的容器的大小。为什么使用 back_inserter不会使这一断言失效?

back_inserter 是插入迭代器,在 iterator.h 头文件中,不是标准库的算法。

练习10.9

实现你自己的elimDups。分别在读取输入后、调用unique后以及调用erase后打印vector的内容。

  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <algorithm>
  5. // print containers like vector, deque, list, etc.
  6. template<typename Sequence>
  7. auto println(Sequence const& seq) -> std::ostream&
  8. {
  9. for (auto const& elem : seq)
  10. std::cout << elem << " ";
  11. return std::cout << std::endl;
  12. }
  13. auto eliminate_duplicates(std::vector<std::string> &vs) -> std::vector<std::string>&
  14. {
  15. std::sort(vs.begin(), vs.end());
  16. println(vs);
  17. auto new_end = std::unique(vs.begin(), vs.end());
  18. println(vs);
  19. vs.erase(new_end, vs.end());
  20. return vs;
  21. }
  22. int main()
  23. {
  24. std::vector<std::string> vs{ "a", "v", "a", "s", "v", "a", "a" };
  25. println(vs);
  26. println(eliminate_duplicates(vs));
  27. return 0;
  28. }

练习10.10

你认为算法不改变容器大小的原因是什么?

解:

  • 将算法和容器的成员函数区分开。
  • 算法的参数是迭代器,不是容器本身。

练习10.11

编写程序,使用 stable_sortisShorter 将传递给你的 elimDups 版本的 vector 排序。打印 vector的内容,验证你的程序的正确性。

解:

  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <algorithm>
  5. #include <numeric>
  6. #include <list>
  7. // print a container like vector, deque, list, etc.
  8. template<typename Sequence>
  9. inline std::ostream& println(Sequence const& seq)
  10. {
  11. for(auto const& elem : seq) std::cout << elem << " ";
  12. std::cout << std::endl;
  13. return std::cout;
  14. }
  15. inline bool
  16. is_shorter(std::string const& lhs, std::string const& rhs)
  17. {
  18. return lhs.size() < rhs.size();
  19. }
  20. void elimdups(std::vector<std::string> &vs)
  21. {
  22. std::sort(vs.begin(), vs.end());
  23. auto new_end = std::unique(vs.begin(), vs.end());
  24. vs.erase(new_end, vs.end());
  25. }
  26. int main()
  27. {
  28. std::vector<std::string> v{
  29. "1234", "1234", "1234", "Hi", "alan", "wang"
  30. };
  31. elimdups(v);
  32. std::stable_sort(v.begin(), v.end(), is_shorter);
  33. std::cout << "ex10.11 :\n";
  34. println(v);
  35. return 0;
  36. }

练习10.12

编写名为 compareIsbn 的函数,比较两个 Sales_data 对象的isbn() 成员。使用这个函数排序一个保存 Sales_data 对象的 vector

解:

  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <algorithm>
  5. #include "../ch07/ex7_26.h" // Sales_data class.
  6. inline bool compareIsbn(const Sales_data &sd1, const Sales_data &sd2)
  7. {
  8. return sd1.isbn().size() < sd2.isbn().size();
  9. }
  10. int main()
  11. {
  12. Sales_data d1("aa"), d2("aaaa"), d3("aaa"), d4("z"), d5("aaaaz");
  13. std::vector<Sales_data> v{ d1, d2, d3, d4, d5 };
  14. // @note the elements the iterators pointing to
  15. // must match the parameters of the predicate.
  16. std::sort(v.begin(), v.end(), compareIsbn);
  17. for(const auto &element : v)
  18. std::cout << element.isbn() << " ";
  19. std::cout << std::endl;
  20. return 0;
  21. }

练习10.13

标准库定义了名为 partition 的算法,它接受一个谓词,对容器内容进行划分,使得谓词为true 的值会排在容器的前半部分,而使得谓词为 false 的值会排在后半部分。算法返回一个迭代器,指向最后一个使谓词为 true 的元素之后的位置。编写函数,接受一个 string,返回一个 bool 值,指出 string 是否有5个或更多字符。使用此函数划分 words。打印出长度大于等于5的元素。

解:

  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <algorithm>
  5. bool predicate(const std::string &s)
  6. {
  7. return s.size() >= 5;
  8. }
  9. int main()
  10. {
  11. auto v = std::vector<std::string>{ "a", "as", "aasss", "aaaaassaa", "aaaaaabba", "aaa" };
  12. auto pivot = std::partition(v.begin(), v.end(), predicate);
  13. for (auto it = v.cbegin(); it != pivot; ++it)
  14. std::cout << *it << " ";
  15. std::cout << std::endl;
  16. return 0;
  17. }

练习10.14

编写一个lambda,接受两个int,返回它们的和。

  1. auto f = [](int i, int j) { return i + j; };

练习10.15

编写一个 lambda ,捕获它所在函数的 int,并接受一个 int参数。lambda 应该返回捕获的 intint 参数的和。

解:

  1. int x = 10;
  2. auto f = [x](int i) { i + x; };

练习10.16

使用 lambda 编写你自己版本的 biggies

解:

  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <algorithm>
  5. // from ex 10.9
  6. void elimdups(std::vector<std::string> &vs)
  7. {
  8. std::sort(vs.begin(), vs.end());
  9. auto new_end = std::unique(vs.begin(), vs.end());
  10. vs.erase(new_end, vs.end());
  11. }
  12. void biggies(std::vector<std::string> &vs, std::size_t sz)
  13. {
  14. using std::string;
  15. elimdups(vs);
  16. // sort by size, but maintain alphabetical order for same size.
  17. std::stable_sort(vs.begin(), vs.end(), [](string const& lhs, string const& rhs){
  18. return lhs.size() < rhs.size();
  19. });
  20. // get an iterator to the first one whose size() is >= sz
  21. auto wc = std::find_if(vs.begin(), vs.end(), [sz](string const& s){
  22. return s.size() >= sz;
  23. });
  24. // print the biggies
  25. std::for_each(wc, vs.end(), [](const string &s){
  26. std::cout << s << " ";
  27. });
  28. }
  29. int main()
  30. {
  31. // ex10.16
  32. std::vector<std::string> v
  33. {
  34. "1234","1234","1234","hi~", "alan", "alan", "cp"
  35. };
  36. std::cout << "ex10.16: ";
  37. biggies(v, 3);
  38. std::cout << std::endl;
  39. return 0;
  40. }

练习10.17

重写10.3.1节练习10.12的程序,在对sort的调用中使用 lambda 来代替函数 compareIsbn

解:

  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <algorithm>
  5. #include "../ch07/ex7_26.h" // Sales_data class.
  6. int main()
  7. {
  8. Sales_data d1("aa"), d2("aaaa"), d3("aaa"), d4("z"), d5("aaaaz");
  9. std::vector<Sales_data> v{ d1, d2, d3, d4, d5 };
  10. std::sort(v.begin(), v.end(), [](const Sales_data &sd1, const Sales_data &sd2){
  11. return sd1.isbn().size() < sd2.isbn().size();
  12. });
  13. for(const auto &element : v)
  14. std::cout << element.isbn() << " ";
  15. std::cout << std::endl;
  16. return 0;
  17. }

练习10.18

重写 biggies,用 partition 代替 find_if。我们在10.3.1节练习10.13中介绍了 partition 算法。

解:

见下题

练习10.19

stable_partition 重写前一题的程序,与 stable_sort 类似,在划分后的序列中维持原有元素的顺序。

解:

  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <algorithm>
  5. // from ex 10.9
  6. void elimdups(std::vector<std::string> &vs)
  7. {
  8. std::sort(vs.begin(), vs.end());
  9. auto new_end = std::unique(vs.begin(), vs.end());
  10. vs.erase(new_end, vs.end());
  11. }
  12. // ex10.18
  13. void biggies_partition(std::vector<std::string> &vs, std::size_t sz)
  14. {
  15. elimdups(vs);
  16. auto pivot = partition(vs.begin(), vs.end(), [sz](const std::string &s){
  17. return s.size() >= sz;}
  18. );
  19. for(auto it = vs.cbegin(); it != pivot; ++it)
  20. std::cout << *it << " ";
  21. }
  22. // ex10.19
  23. void biggies_stable_partition(std::vector<std::string> &vs, std::size_t sz)
  24. {
  25. elimdups(vs);
  26. auto pivot = stable_partition(vs.begin(), vs.end(), [sz](const std::string& s){
  27. return s.size() >= sz;
  28. });
  29. for(auto it = vs.cbegin(); it != pivot; ++it)
  30. std::cout << *it << " ";
  31. }
  32. int main()
  33. {
  34. // ex10.18
  35. std::vector<std::string> v{
  36. "the", "quick", "red", "fox", "jumps", "over", "the", "slow", "red", "turtle"
  37. };
  38. std::cout << "ex10.18: ";
  39. std::vector<std::string> v1(v);
  40. biggies_partition(v1, 4);
  41. std::cout << std::endl;
  42. // ex10.19
  43. std::cout << "ex10.19: ";
  44. std::vector<std::string> v2(v);
  45. biggies_stable_partition(v2, 4);
  46. std::cout << std::endl;
  47. return 0;
  48. }

练习10.20

标准库定义了一个名为 count_if 的算法。类似 find_if,此函数接受一对迭代器,表示一个输入范围,还接受一个谓词,会对输入范围中每个元素执行。count_if返回一个计数值,表示谓词有多少次为真。使用count_if重写我们程序中统计有多少单词长度超过6的部分。

解:

  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <algorithm>
  5. using std::vector;
  6. using std::count_if;
  7. using std::string;
  8. // Exercise 10.20
  9. std::size_t bigerThan6(vector<string> const& v)
  10. {
  11. return count_if(v.cbegin(), v.cend(), [](string const& s){
  12. return s.size() > 6;
  13. });
  14. }
  15. int main()
  16. {
  17. // ex10.20
  18. vector<string> v{
  19. "alan","moophy","1234567","1234567","1234567","1234567"
  20. };
  21. std::cout << "ex10.20: " << bigerThan6(v) << std::endl;
  22. // ex10.21
  23. int i = 7;
  24. auto check_and_decrement = [&i]() { return i > 0 ? !--i : !i; };
  25. std::cout << "ex10.21: ";
  26. while(!check_and_decrement())
  27. std::cout << i << " ";
  28. std::cout << i << std::endl;
  29. return 0;
  30. }

练习10.21

编写一个 lambda,捕获一个局部 int 变量,并递减变量值,直至它变为0。一旦变量变为0,再调用lambda应该不再递减变量。lambda应该返回一个bool值,指出捕获的变量是否为0。

解:

  1. int i = 10;
  2. auto f = [&i]() -> bool { return (i == 0 ? true : !(i--)); };
  3. while (!f()) cout << i << endl;

练习10.22

重写统计长度小于等于6的单词数量的程序,使用函数代替lambda

  1. #include <iostream>
  2. #include <vector>
  3. #include <string>
  4. #include <algorithm>
  5. #include <functional>
  6. using std::string;
  7. using namespace std::placeholders;
  8. bool isLesserThanOrEqualTo6(const string &s, string::size_type sz)
  9. {
  10. return s.size() <= sz;
  11. }
  12. int main()
  13. {
  14. std::vector<string> authors{ "Mooophy", "pezy", "Queequeg90", "shbling", "evan617" };
  15. std::cout << count_if(authors.cbegin(), authors.cend(), bind(isLesserThanOrEqualTo6, _1, 6));
  16. }

练习10.23

bind 接受几个参数?

假设被绑定的函数接受 n 个参数,那么bind 接受n + 1个参数。

练习10.24

给定一个string,使用 bindcheck_size 在一个 intvector 中查找第一个大于string长度的值。

解:

  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. #include <functional>
  5. using std::cout;
  6. using std::endl;
  7. using std::string;
  8. using std::vector;
  9. using std::find_if;
  10. using std::bind;
  11. using std::size_t;
  12. auto check_size(string const& str, size_t sz)
  13. {
  14. return str.size() < sz;
  15. }
  16. int main()
  17. {
  18. vector<int> vec{ 0, 1, 2, 3, 4, 5, 6, 7 };
  19. string str("123456");
  20. auto result = find_if(vec.begin(), vec.end(), bind(check_size, str, std::placeholders::_1));
  21. if (result != vec.end())
  22. cout << *result << endl;
  23. else
  24. cout << "Not found" << endl;
  25. return 0;
  26. }

练习10.25

在10.3.2节的练习中,编写了一个使用partitionbiggies版本。使用 check_sizebind 重写此函数。

解:

  1. #include <iostream>
  2. #include <vector>
  3. #include <string>
  4. #include <algorithm>
  5. #include <functional>
  6. using std::string; using std::vector;
  7. using namespace std::placeholders;
  8. void elimdups(vector<string> &vs)
  9. {
  10. std::sort(vs.begin(), vs.end());
  11. vs.erase(unique(vs.begin(), vs.end()), vs.end());
  12. }
  13. bool check_size(const string &s, string::size_type sz)
  14. {
  15. return s.size() >= sz;
  16. }
  17. void biggies(vector<string> &words, vector<string>::size_type sz)
  18. {
  19. elimdups(words);
  20. auto iter = std::stable_partition(words.begin(), words.end(), bind(check_size, _1, sz));
  21. for_each(words.begin(), iter, [](const string &s){ std::cout << s << " "; });
  22. }
  23. int main()
  24. {
  25. std::vector<std::string> v{
  26. "the", "quick", "red", "fox", "jumps", "over", "the", "slow", "red", "turtle"
  27. };
  28. biggies(v, 4);
  29. }

练习10.26

解释三种插入迭代器的不同之处。

解:

  • back_inserter 使用 push_back
  • front_inserter 使用 push_front
  • inserter 使用 insert,此函数接受第二个参数,这个参数必须是一个指向给定容器的迭代器。元素将被插入到给定迭代器所表示的元素之前。

练习10.27

除了 unique 之外,标准库还定义了名为 unique_copy 的函数,它接受第三个迭代器,表示拷贝不重复元素的目的位置。编写一个程序,使用 unique_copy将一个vector中不重复的元素拷贝到一个初始化为空的list中。

解:

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <vector>
  4. #include <list>
  5. #include <iterator>
  6. int main()
  7. {
  8. std::vector<int> vec{ 1, 1, 3, 3, 5, 5, 7, 7, 9 };
  9. std::list<int> lst;
  10. std::unique_copy(vec.begin(), vec.end(), back_inserter(lst));
  11. for (auto i : lst)
  12. std::cout << i << " ";
  13. std::cout << std::endl;
  14. }

练习10.28

一个vector 中保存 1 到 9,将其拷贝到三个其他容器中。分别使用inserterback_inserterfront_inserter 将元素添加到三个容器中。对每种 inserter,估计输出序列是怎样的,运行程序验证你的估计是否正确。

解:

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <vector>
  4. #include <list>
  5. #include <iterator>
  6. using std::list; using std::copy; using std::cout; using std::endl;
  7. template<typename Sequence>
  8. void print(Sequence const& seq)
  9. {
  10. for (const auto& i : seq)
  11. std::cout << i << " ";
  12. std::cout << std::endl;
  13. }
  14. int main()
  15. {
  16. std::vector<int> vec{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  17. // uses inserter
  18. list<int> lst1;
  19. copy(vec.cbegin(), vec.cend(), inserter(lst1, lst1.begin()));
  20. print(lst1);
  21. // uses back_inserter
  22. list<int> lit2;
  23. copy(vec.cbegin(), vec.cend(), back_inserter(lit2));
  24. print(lit2);
  25. // uses front_inserter
  26. list<int> lst3;
  27. copy(vec.cbegin(), vec.cend(), front_inserter(lst3));
  28. print(lst3);
  29. }

前两种为正序,第三种为逆序,输出和预计一样。

练习10.29

编写程序,使用流迭代器读取一个文本文件,存入一个vector中的string里。

解:

  1. #include <iostream>
  2. #include <fstream>
  3. #include <vector>
  4. #include <string>
  5. #include <iterator>
  6. using std::string;
  7. int main()
  8. {
  9. std::ifstream ifs("../data/book.txt");
  10. std::istream_iterator<string> in(ifs), eof;
  11. std::vector<string> vec;
  12. std::copy(in, eof, back_inserter(vec));
  13. // output
  14. std::copy(vec.cbegin(), vec.cend(), std::ostream_iterator<string>(std::cout, "\n"));
  15. }

练习10.30

使用流迭代器、sortcopy 从标准输入读取一个整数序列,将其排序,并将结果写到标准输出。

解:

  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. #include <iterator>
  5. using namespace std;
  6. int main()
  7. {
  8. vector<int> v;
  9. istream_iterator<int> int_it(cin), int_eof;
  10. copy(int_it, int_eof, back_inserter(v));
  11. sort(v.begin(), v.end());
  12. copy(v.begin(), v.end(), ostream_iterator<int>(cout," "));
  13. cout << endl;
  14. return 0;
  15. }

练习10.31

修改前一题的程序,使其只打印不重复的元素。你的程序应该使用 unique_copy

解:

  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. #include <iterator>
  5. using namespace std;
  6. int main()
  7. {
  8. vector<int> v;
  9. istream_iterator<int> int_it(cin), int_eof;
  10. copy(int_it, int_eof, back_inserter(v));
  11. sort(v.begin(), v.end());
  12. unique(v.begin(), v.end());
  13. copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
  14. cout << endl;
  15. return 0;
  16. }

练习10.32

重写1.6节中的书店程序,使用一个vector保存交易记录,使用不同算法完成处理。使用 sort 和10.3.1节中的 compareIsbn 函数来排序交易记录,然后使用 findaccumulate 求和。

解:

  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. #include <iterator>
  5. #include <numeric>
  6. #include "../include/Sales_item.h"
  7. int main()
  8. {
  9. std::istream_iterator<Sales_item> in_iter(std::cin), in_eof;
  10. std::vector<Sales_item> vec;
  11. while (in_iter != in_eof)
  12. vec.push_back(*in_iter++);
  13. sort(vec.begin(), vec.end(), compareIsbn);
  14. for (auto beg = vec.cbegin(), end = beg; beg != vec.cend(); beg = end) {
  15. end = find_if(beg, vec.cend(), [beg](const Sales_item &item){ return item.isbn() != beg->isbn(); });
  16. std::cout << std::accumulate(beg, end, Sales_item(beg->isbn())) << std::endl;
  17. }
  18. }

练习10.33

编写程序,接受三个参数:一个输入文件和两个输出文件的文件名。输入文件保存的应该是整数。使用 istream_iterator 读取输入文件。使用 ostream_iterator 将奇数写入第一个输入文件,每个值后面都跟一个空格。将偶数写入第二个输出文件,每个值都独占一行。

解:

  1. #include <fstream>
  2. #include <iterator>
  3. #include <algorithm>
  4. int main(int argc, char **argv)
  5. {
  6. if (argc != 4) return -1;
  7. std::ifstream ifs(argv[1]);
  8. std::ofstream ofs_odd(argv[2]), ofs_even(argv[3]);
  9. std::istream_iterator<int> in(ifs), in_eof;
  10. std::ostream_iterator<int> out_odd(ofs_odd, " "), out_even(ofs_even, "\n");
  11. std::for_each(in, in_eof, [&out_odd, &out_even](const int i)
  12. {
  13. *(i & 0x1 ? out_odd : out_even)++ = i;
  14. });
  15. return 0;
  16. }

练习10.34

使用 reverse_iterator 逆序打印一个vector

解:

  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. int main()
  5. {
  6. vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  7. for (auto it = v.crbegin(); it != v.crend(); ++it)
  8. {
  9. cout << *it << endl;
  10. }
  11. return 0;
  12. }

练习10.35

使用普通迭代器逆序打印一个vector

解:

  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. int main()
  5. {
  6. vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  7. for (auto it = std::prev(v.cend()); true; --it)
  8. {
  9. std::cout << *it << " ";
  10. if (it == v.cbegin()) break;
  11. }
  12. std::cout << std::endl;
  13. return 0;
  14. }

练习10.36

使用 find 在一个 intlist 中查找最后一个值为0的元素。

解:

  1. #include <iostream>
  2. #include <list>
  3. #include <algorithm>
  4. using namespace std;
  5. int main()
  6. {
  7. list<int> l = { 1, 2, 0, 4, 5, 6, 7, 0, 9 };
  8. auto it = find(l.crbegin(), l.crend(), 0);
  9. cout << distance(it, l.crend()) << endl;
  10. return 0;
  11. }

练习10.37

给定一个包含10 个元素的vector,将位置3到7之间的元素按逆序拷贝到一个list中。

解:

  1. #include <iostream>
  2. #include <list>
  3. #include <algorithm>
  4. #include <vector>
  5. #include <iterator>
  6. using namespace std;
  7. int main()
  8. {
  9. vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  10. list<int> l;
  11. copy(v.crbegin() + 3, v.crbegin() + 8, back_inserter(l));
  12. for (auto i : l) std::cout << i << " ";
  13. cout << endl;
  14. return 0;
  15. }

练习10.38

列出5个迭代器类别,以及每类迭代器所支持的操作。

  • 输入迭代器 : ==,!=,++,*,->
  • 输出迭代器 : ++,*
  • 前向迭代器 : ==,!=,++,*,->
  • 双向迭代器 : ==,!=,++,--,*,->
  • 随机访问迭代器 : ==,!=,<,<=,>,>=,++,--,+,+=,-,-=,*,->,iter[n]==*(iter[n])

练习10.39

list 上的迭代器属于哪类?vector呢?

  • list 上的迭代器是 双向迭代器
  • vector 上的迭代器是 随机访问迭代器

练习10.40

你认为 copy 要求哪类迭代器?reverseunique 呢?

  • copy 需要两个输入迭代器,一个输出迭代器
  • reverse 需要双向迭代器
  • unique需要随机访问迭代器

练习10.41

仅根据算法和参数的名字,描述下面每个标准库算法执行什么操作:

  1. replace(beg, end, old_val, new_val);
  2. replace_if(beg, end, pred, new_val);
  3. replace_copy(beg, end, dest, old_val, new_val);
  4. replace_copy_if(beg, end, dest, pred, new_val);

解:

  • replace 在迭代器范围内用新值替换所有原来的旧值。
  • replace_if 在迭代器范围内,满足谓词条件的元素用新值替换。
  • replace_copy 复制迭代器范围内的元素到目标迭代器位置,如果元素等于某个旧值,则用新值替换
  • replace_copy_if 复制迭代器范围内的元素到目标迭代器位置,满足谓词条件的元素用新值替换

练习10.42

使用 list 代替 vector 重新实现10.2.3节中的去除重复单词的程序。

解:

  1. #include <iostream>
  2. #include <string>
  3. #include <list>
  4. using std::string; using std::list;
  5. void elimDups(list<string> &words)
  6. {
  7. words.sort();
  8. words.unique();
  9. }
  10. int main()
  11. {
  12. list<string> l = { "aa", "aa", "aa", "aa", "aasss", "aa" };
  13. elimDups(l);
  14. for (const auto& e : l)
  15. std::cout << e << " ";
  16. std::cout << std::endl;
  17. }