答:accumulate的第三个参数是和的初始值,它还决定了函数的返回类型,以及函数中使用哪个加法运算符。
因此,本题中的调用是错误的,第三个参数0告知accumulate,和是整型的,使用整型加法运算符。正确的调用方法是将0.0作为第三个参数传递给accumulate。
练习 10.5:在本节对名册(roster)调用equal 的例子中,如果两个名册中保存的都是c 风格字符串而不是string,会发生什么?
答:equal使用==运算符比较两个序列中的元素。string类重载了==,可比较两个字符串是否长度相等且其中元素对位相等。而C风格字符串本质是char *类型,用==比较两个char *对象,只是检查两个指针值是否相等,即地址是否相等,而不会比较其中字符是否相同。所以,只有当两个序列中的指针都指向相同的地址时,equal才会返回true,否则,即使字符串内容完全相同,也会返回false。
练习 10.6:编写程序,使用fill_n 将一个序列中的int 值都设置为0 。
//练习 10.6
#include
#include
#include
#include
using namespace std;
int main(int argc, char * argv[])
{
ifstream in(argv[1]);
if (!in)
{
cout << "打开输入文件失败!" << endl;
return -1;
}
vector vi;
int val;
while (in >> val)
{
vi.push_back(val);
cout << val << " ";
}
cout << endl;
fill_n(vi.begin(), vi.size(), 0);
for (auto iter = vi.begin(); iter != vi.end(); ++iter)
{
cout << *iter << endl;
}
system("pause");
return 0;
}
练习 10.7:下面程序是否有错误?如果有,请改正。
(a) vector vec; list lst; int i;
while(cin >> i)
lst.push_back(i);
copy(lst.begin(), lst,end(), vec.begin());
(b) vector vec;
vec.reserve(10);
fill_n(vec.begin(), 10, 0);
(a)有错误,copy算法要求目标序列至少要包含与源序列一样多的元素,而此程序中,vec进行缺省初始化,它是空的,copy无法进行。可以将第三个参数改为back_inserter(vec),通过它,copy算法即可将lst中的元素拷贝插入到lst的末尾。
(b)也有错误。此时,vec仍然为空,没有任何元素。而算法又不具备向容器添加元素的能力,因此fill_n仍然失败。这里还是将第一个参数改成back_inserter(vec)来让fill_n有能力向vec添加元素。
练习 10.8:本节提到过,标准库算法不会改变它们所操作的容器的大小。为什么使用back_inserter 不会使这一断言失效?
答:标准库算法根本不知道有“容器”这个东西。它们只接受迭代器参数,运行于这些迭代器之上,通过这些迭代器来访问元素。
因此,当传递给算法普通迭代器时,这些迭代器只能顺序或者随机访问容器中的元素,造成的效果就是算法只能读取元素、改变元素、移动元素,但无法添加或者删除元素。
当我们传递给算法插入器,例如back_inserter时,由于这类迭代器能调用下层容器的操作来向容器插入元素,造成算法执行的效果就是向容器中添加了元素。
标准库算法从来不直接操作容器,它们只操作迭代器,从而间接访问容器。能不能插入和删除元素,不在于算法,而在于传递给它们的迭代器是否具有这样的能力。
练习 10.9:实现你自己的elimDups 。测试你的程序, 分别在读取输入后、调用unique后以及调用erase 后打印vector 的内容。
//练习 10.9
#include
#include
#include
#include
#include
using namespace std;
void elimDups(vector & words)
{
cout << "原始vector的元素为:" << endl;
//打印原始vector
for (auto & r : words)
cout << r << " ";
cout << endl;
//sort对vector中的元素进行重排序
sort(words.begin(), words.end());
cout << "排序之后的vector元素为:" << endl;
//打印排序之后的vector
for (auto & r : words)
cout << r << " ";
cout << endl;
//unique并没有删除元素,只是让不重复的元素出现在前面,
//返回一个指向不重复范围末尾的迭代器,
//即相当于把重复的元素都放在了后面
auto end_unique = unique(words.begin(), words.end());
cout << "unique之后的vector元素为:" << endl;
for (auto & r : words)
cout << r << " ";
cout << endl;
//最后利用容器自身的操作删除重复的元素
words.erase(end_unique, words.end());
cout << "erase之后的vector元素为:" << endl;
for (auto & r : words)
cout << r << " ";
cout << endl;
}
int main(int argc, char * argv[])
{
if (argc != 2)
{
cout << "请正确输入文件名!" << endl;
return -1;
}
//打开文件
ifstream in(argv[1]);
if (!in)
{
cout << "无法打开文件!" << endl;
return -1;
}
vector svec;
string s;
while (in >> s)
{
svec.push_back(s);
}
elimDups(svec);
system("pause");
return 0;
}
练习 10.10:你认为算法不改变容器大小的原因是什么?
答:泛型算法的一大优点是“泛型”,也就是一个算法可用于多种不同的数据结构,算法与所操作的数据结构分离。要做到算法与数据结构分离,重要的技术手段就是使用迭代器作为两者的桥梁。算法从不操作具体的容器,从而也就不存在与特定容器绑定,不适用于其他容器的问题。算法只操作迭代器,由迭代器真正实现对容器的访问。不同容器实现自己特定的迭代器,算法操作不同的迭代器就实现了对不同容器的访问。
因此,并不是算法应该改变或不改变容器的问题。为了实现与数据结构的分离,为了实现通用性,算法根本就不该知道容器的存在。算法访问数据的唯一通道是迭代器。是否改变容器大小,完全是迭代器的选择和责任。
练习 10.11:编写程序,使用stable_sort 和isShorter 将传递给你的elimDups版本的vector 排序。打印vector 的内容, 验证你的程序的正确性。
//练习 10.11
#include
#include
#include
#include
#include
using namespace std;
bool isShorter(const string & s1, const string & s2)
{
return s1.size() < s2.size();
}
inline void output(vector & svec)
{
for (auto & r : svec)
cout << r << " ";
cout << endl;
}
void elimDups(vector & words)
{
cout << "原始vector的元素为:" << endl;
//打印原始vector
output(words);
//sort对vector中的元素进行重排序
sort(words.begin(), words.end());
cout << "排序之后的vector元素为:" << endl;
//打印排序之后的vector
output(words);
//unique并没有删除元素,只是让不重复的元素出现在前面,
//返回一个指向不重复范围末尾的迭代器,
//即相当于把重复的元素都放在了后面
auto end_unique = unique(words.begin(), words.end());
cout << "unique之后的vector元素为:" << endl;
output(words);
//最后利用容器自身的操作删除重复的元素
words.erase(end_unique, words.end());
cout << "erase之后的vector元素为:" << endl;
output(words);
//用stable_sort来重排元素
stable_sort(words.begin(), words.end(), isShorter);
cout << "stable_sort之后的vector元素为:" << endl;
output(words);
}
int main(int argc, char * argv[])
{
if (argc != 2)
{
cout << "请正确输入文件名!" << endl;
return -1;
}
//打开文件
ifstream in(argv[1]);
if (!in)
{
cout << "无法打开文件!" << endl;
return -1;
}
vector svec;
string s;
while (in >> s)
{
svec.push_back(s);
}
elimDups(svec);
system("pause");
return 0;
}
练习 10.12:编写名为compareIsbn 的函数,比较两个Sales_data 对象的isbn() 成员。使用这个函数排序一个保存Sales_data 对象的vector。
inline bool compareIsbn(const Sales_data & lhs, const Sales_data & rhs)
{
return lhs.isbn() < rhs.isbn();
}
练习 10.13:标准库定义了名为partition 的算法,它接受一个谓词,对容器内容进行划分,使得谓词为true 的值会排在容器的前半部分,而使谓词为false 的值会排在后半部分。算法返回一个法代器,指向最后一个使谓词为true 的元素之后的位置。编写函数,接受一个string,返回一个bool 值,指出string 是否有5 个或更多字符。使用此函数划分words 。打印出长度大于等于5 的元素。
//练习 10.13
#include
#include
#include
#include
#include
using namespace std;
//利用迭代器输出vector中的元素。
inline void output_words(vector::iterator beg, vector::iterator end)
{
for (auto iter = beg; iter != end; ++iter)
cout << *iter << " ";
cout << endl;
}
//长度超过5的单词
bool five_or_more(const string &s)
{
return s.size() >= 5;
}
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if (!in){
cout << "无法打开文件。" << endl;
return -1;
}
string word;
vector vec;
while (in >> word)
vec.push_back(word);
//partition返回一个迭代器,指向最后一个使谓词为true的元素之后
auto iter = partition(vec.begin(), vec.end(), five_or_more);
output_words(vec.begin(), iter);
cout << endl;
system("pause");
return 0;
}
练习 10.14:编写一个lambda,接受两个int ,返回它们的和。
// 练习 10.14
[](int a, int b){ return a + b; }
练习 10.15:编写一个lambda,捕获它所在函数的int,并接受一个int 参数。lambda应该返回捕获的int 和int 参数的和。
// 练习 10.15
#include
using namespace std;
void add(int a)
{
//可调用对象
auto sum = [a](int b) { return a + b; };
cout << sum(1) << endl;
}
int main()
{
add(1);
add(2);
system("pause");
return 0;
}
练习 10.16:使用lambda 编写你自己版本的biggies 。
// 练习 10.16
#include
#include
#include
#include
#include
using namespace std;
string make_plural(size_t ctr, const string &word, const string &ending)
{
return (ctr>1) ? word + ending : word;
}
void elimdups(vector &words)
{
sort(words.begin(), words.end());
auto end_unique = unique(words.begin(), words.end());
words.erase(end_unique, words.end());
}
void biggies(vector &words, vector::size_type sz)
{
elimdups(words); //将words按字典序排序,删除重复词
// 按长度排序,长度相同的单词维持字典序
stable_sort(words.begin(), words.end(), [](const string &a, const string &b){return a.size()=sz的元素
auto wc = find_if(words.begin(), words.end(), [sz](const string &a){return a.size() >= sz; });
// 计算满足size()>=sz的元素的数目
auto count = words.end() - wc;
cout << count << " " << make_plural(count, "word", "s") << " of length " << sz << " or longer" << endl;
// 打印长度大于等于给定值的单词,每个单词后面接一个空格
for_each(wc, words.end(), [](const string &s){cout << s << " "; });
cout << endl;
}
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if (!in){
cout << "Open input file failed." << endl;
return -1;
}
string str;
vector vec;
while (in >> str)
vec.push_back(str);
biggies(vec, 5);
system("pause");
return 0;
}
练习 10.17:重写10.3.1节练习10.12(第345 页)的程序, 在对sort 的调用中使用lambda来代替函数compareIsbn。
sort(Sales_data_object.begin(), Sales_data_object.end(),
[] (Sales_data & lhs, Sales_data & rhs) { return lhs.isbn() < rhs.isbn(); });
练习 10.18:重写biggies,用partition 代替find_if 。我们在10.3.1节练习10.13(第345 页)中介绍了partition 算法。
// 练习 10.18
#include
#include
#include
#include
#include
using namespace std;
string make_plural(size_t ctr, const string &word, const string &ending)
{
return (ctr>1) ? word + ending : word;
}
void elimdups(vector &words)
{
sort(words.begin(), words.end());
auto end_unique = unique(words.begin(), words.end());
words.erase(end_unique, words.end());
}
void biggies(vector &words, vector::size_type sz)
{
elimdups(words); //将words按字典序排序,删除重复词
// 获取一个迭代器,指向最后一个size()>=sz的元素的后面
auto wc = partition(words.begin(), words.end(), [sz](const string &a){return a.size() >= sz; });
// 计算满足size()>=sz的元素的数目
auto count = wc - words.begin();
cout << count << " " << make_plural(count, "word", "s") << " of length " << sz << " or longer" << endl;
// 打印长度大于等于给定值的单词,每个单词后面接一个空格
for_each(words.begin(), wc, [](const string &s){cout << s << " "; });
cout << endl;
}
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if (!in){
cout << "Open input file failed." << endl;
return -1;
}
string str;
vector vec;
while (in >> str)
vec.push_back(str);
biggies(vec, 5);
system("pause");
return 0;
}
对于本题而言,如果使用find_if,要求序列已按字符串长度递增顺序排好序,而partition不要求序列已排序,他对所有字符串检查长度是否满足要求,将满足要求的字符串移动到序列前段,不满足条件的字符串都移动到满足条件的字符串之后。
练习 10.19:用stable_partition重写前一题的程序,与stable_sort 类似, 在划分后的序列中维持原有元素的顺序。
//练习 10.19
#include
#include
#include
#include
#include
using namespace std;
string make_plural(size_t ctr, const string &word, const string &ending)
{
return (ctr>1) ? word + ending : word;
}
void elimdups(vector &words)
{
sort(words.begin(), words.end());
auto end_unique = unique(words.begin(), words.end());
words.erase(end_unique, words.end());
}
void biggies(vector &words, vector::size_type sz)
{
elimdups(words); //将words按字典序排序,删除重复词
按长度排序,长度相同的单词维持字典序
//stable_sort(words.begin(), words.end(), [](const string &a, const string &b){return a.size()=sz的元素的后面
auto wc = stable_partition(words.begin(), words.end(), [sz](const string &a){return a.size() >= sz; });
// 计算满足size()>=sz的元素的数目
auto count = wc - words.begin();
cout << count << " " << make_plural(count, "word", "s") << " of length " << sz << " or longer" << endl;
// 打印长度大于等于给定值的单词,每个单词后面接一个空格
for_each(words.begin(), wc, [](const string &s){cout << s << " "; });
cout << endl;
}
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if (!in){
cout << "Open input file failed." << endl;
return -1;
}
string str;
vector vec;
while (in >> str)
vec.push_back(str);
biggies(vec, 5);
system("pause");
return 0;
}
stable_partition和partition相比,就是对满足要求的元素还排了序。
练习 10.20:标准库定义了一个名为count_if 的算法。类似find_if ,此函数接受一对迭代器,表示一个输入范围,还接受一个谓词,会对输入范围中每个元素执行。count_if 返回一个计数值,表示谓词有多少次为真。使用count_if 重写我们程序中统计有多少单词长度超过6 的部分。
#ifndef MAKE_PLURAL_H
#define MAKE_PLURAL_H
#include
using std::string; //头文件中记得要加这个!
string make_plural(size_t ctr, const string &word, const string &ending)
{
return (ctr>1) ? word + ending : word;
}
#endif
练习 10.21:编写一个lambda,捕获一个局部int 变量,并递减变量值,直至它变为0。一旦变量变为0,再调用lambda 应该不再递减变量。lambda应该返回一个bool值,指出捕获的变量是否为0 。
// 练习 10.21
#include
#include
using namespace std;
void mutable_lambda()
{
int i = 5;
auto f = [i]() mutable -> bool { if (i > 0) { --i; return false; } else return true; };
for (int j = 0; j < 6; ++j)
{
//调用lambda,lambda的调用方式和普通函数的调用方式一样
cout << f() << " ";
}
cout << endl;
}
int main()
{
mutable_lambda();
system("pause");
return 0;
}
练习 10.22:重写统计长度小于等于6 的单词数量的程序,使用函数代替lambda 。
// 练习 10.22
#include
#include
#include
#include
#include
#include
#include "make_plural.h"
using namespace std;
using namespace std::placeholders; //_n定义在命名空间std::placeholders中
//检查单词长度,返回长度小于等于6的
bool check_size(const string & s, string::size_type sz)
{
return s.size() <= sz;
}
//利用迭代器输出vector的内容
inline void output_words(vector & words)
{
for (auto iter = words.begin(); iter != words.end(); ++iter)
{
cout << *iter << " ";
}
cout << endl;
}
void biggies(vector &words, vector::size_type sz)
{
output_words(words);
// 统计满足size() >= sz的元素的个数
auto bc = count_if(words.begin(), words.end(),
bind(check_size, _1, sz));
cout << bc << " " << make_plural(bc, "word", "s")
<< " of length " << sz << " or longer" << endl;
}
int main(int argc, char * argv[])
{
ifstream in(argv[1]);
if (!in)
{
cout << "无法打开输入文件!" << endl;
return -1;
}
vector words;
string word;
while (in >> word)
{
words.push_back(word);
}
biggies(words, 6);
system("pause");
return 0;
}
练习 10.23:bind 接受几个参数?
答:bind是可变参数的。它接受的第一个参数是一个可调用对象,即实际工作函数A,返回供算法使用的新的可调用对象B。若A接受x个参数,则bind的参数个数应该是x+1,即除了A外,其他参数应一一对应A所接受的参数。这些参数中有一部分来自于B(_n),另外一些来自于所处函数的局部变量。
练习 10.24:给定一个string,使用bind 和check_size 在一个int 的vector中查找第一个大于string 长度的值。
// 练习 10.24
#include
#include
#include
#include
#include
using namespace std;
using namespace::placeholders;
//这里或许应该是int sz。
bool check_size(const string &s, string::size_type sz)
{
return s.size() <= sz;
}
void biggies(vector & vc, const string & s)
{
// 查找第一个大于等于s长度的数值
//这里的_1表示的是每次对vector中int元素调用bind函数时传递进去的值。
auto p = find_if(vc.begin(), vc.end(), bind(check_size, s, _1));
// 打印结果
cout << "第" << p - vc.begin() + 1 << "个数" << *p << "大于等于" << s << "的长度" << endl;
cout << endl;
}
int main(int argc, char *argv[])
{
vector vc = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
biggies(vc, "hello");
biggies(vc, "everyone");
biggies(vc, "!");
system("pause");
return 0;
}
练习 10.25:在10.3.2节(第349 页)的练习中,编写了一个使用partition 的biggies版本。使用check_size 和bind 重写此函数。
// 练习 10.25
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace std::placeholders;
string make_plural(size_t ctr, const string &word, const string &ending)
{
return (ctr>1) ? word + ending : word;
}
//对vector进行排序并且删除重复的元素。
void elimdups(vector &words)
{
sort(words.begin(), words.end());
auto end_unique = unique(words.begin(), words.end());
words.erase(end_unique, words.end());
}
bool check_size(const string &s, string::size_type sz)
{
return s.size() >= sz;
}
void biggies(vector &words, vector::size_type sz)
{
//打印words中的内容
for_each(words.begin(), words.end(), [](const string &s){cout << s << " "; });
cout << endl;
elimdups(words); //将words按字典序排序,删除重复词
// 按长度排序,长度相同的单词维持字典序
stable_sort(words.begin(), words.end(), [](const string &a, const string &b){return a.size()=sz的元素的后面
auto wc = partition(words.begin(), words.end(), bind(check_size, _1, sz));
// 计算满足size()>=sz的元素的数目
auto count = wc - words.begin();
cout << count << " " << make_plural(count, "word", "s") << " of length " << sz << " or longer" << endl;
// 打印长度大于等于给定值的单词,每个单词后面接一个空格
for_each(words.begin(), wc, [](const string &s){cout << s << " "; });
cout << endl;
}
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if (!in){
cout << "Open input file failed." << endl;
return -1;
}
string str;
vector vec;
while (in >> str)
vec.push_back(str);
biggies(vec, 5);
system("pause");
return 0;
}
练习 10.26:解释三种插入迭代器的不同之处。
答:三者的差异在于如何向容器插入元素:back_inserter调用push_back,front_inserter 调用push_front,inserter则调用inserter。这决定了它们插入元素位置的不同。back_inserter总是插入到容器尾元素之后,front_inserter 总是插入到元素首元素之前,而inserter则是插入到给定位置之前。
练习 10.27:除了unique(参见10.2.3 节,第343 页)之外,标准库还定义了名为unique_copy 的函数, 它接受第三个迭代器,表示拷贝不重复元素的目的位置。编写一个程序,使用unique_copy 将一个vector 中不重复的元素拷贝到一个初始为空的list 中。
//练习 10.27
#include
#include
#include
#include
//迭代器定义的头文件
#include
using namespace std;
int main()
{
vector ivec = { 1, 2, 2, 3, 4, 5, 5, 6 };
list ilist;
//unique_copy接收第三个迭代器,表示拷贝不重复元素的目的位置。
//unique_copy(ivec.begin(), ivec.end(), back_inserter(ilist));
unique_copy(ivec.begin(), ivec.end(), inserter(ilist, ilist.begin()));
for (auto v : ilist)
cout << v << " ";
cout << endl;
system("pause");
return 0;
}
练习 10.28:一个vector中保存1到9,将其拷贝到三个其他容器中。分别使用inserter 、back_inserter 和front_inserter 将元素添加到三个容器中。对每种inserter,估计输出序列是怎样的,运行程序验证你的估计是否正确。
//练习 10.28
#include
#include
#include
#include
#include
using namespace std;
int main()
{
vector ivec{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
list ilist1, ilist2, ilist3;
//三种方法将vector中的元素添加到list中。
copy(ivec.begin(), ivec.end(), front_inserter(ilist1));
copy(ivec.begin(), ivec.end(), inserter(ilist2, ilist2.begin()));
copy(ivec.begin(), ivec.end(), back_inserter(ilist3));
for (auto &r : ilist1)
cout << r << " ";
cout << endl;
for (auto &r : ilist2)
cout << r << " ";
cout << endl;
for (auto &r : ilist3)
cout << r << " ";
cout << endl;
system("pause");
return 0;
}
练习 10.29:编写程序, 使用流迭代器读取一个文本文件,存入一个vector 中的string里。
//练习 10.29
#include
#include
#include
#include
#include
using namespace std;
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if (!in)
{
cout << "打开输入文件失败!" << endl;
return -1;
}
//创建流迭代器从文件读入字符串
istream_iterator in_iter(in);
istream_iterator eof;
vector words;
while (in_iter != eof)
{
words.push_back(*in_iter++);
}
for (auto word : words)
cout << word << " ";
cout << endl;
system("pause");
return 0;
}
练习 10.30:使用流迭代器、sort 和copy 从标准输入读取一个整数序列,将其排序,并将结果写到标准输出。
//练习 10.30
#include
#include
#include
#include
using namespace std;
int main()
{
//创建流迭代器从标准输入读入整数
istream_iterator in_iter(cin);
//尾后迭代器
istream_iterator eof;
vector ivec;
while (in_iter != eof)
{
ivec.push_back(*in_iter++);
}
//sort排序
sort(ivec.begin(), ivec.end());
ostream_iterator out_iter(cout, " ");
copy(ivec.begin(), ivec.end(), out_iter);
system("pause");
return 0;
}
练习 10.31:修改前一题的程序,使其只打印不重复的元素。你的程序应使用unique_copy (参见10.4.1节,第359 页) 。
//练习 10.31
#include
#include
#include
#include
using namespace std;
int main()
{
//创建流迭代器从标准输入读取整数
istream_iterator in_iter(cin);
//尾后迭代器
istream_iterator eof;
vector ivec;
while (in_iter != eof)
{
ivec.push_back(*in_iter++);
}
//排序
sort(ivec.begin(), ivec.end());
//输出流迭代器
ostream_iterator out_iter(cout, " ");
unique_copy(ivec.begin(), ivec.end(), out_iter);
system("pause");
return 0;
}
练习 10.32:重写1.6节(第21页)中的书店程序,使用一个vector 保存交易记录,使用不同算法完成处理。使用sort 和10.3.1节(第345 页)中的compareisbn 函数来排序交易记录,然后使用find和accumulate 求和。
待定。
练习 10.33:编写程序,接受三个参数: 一个输入文件和两个输出文件的文件名。输入文件保存的应该是整数。使用istream_iterator 读取输入文件。使用ostream_iterator 将奇数写入第一个输出文件,每个值之后都跟一个空格。将偶数写入第二个输出文件, 每个值都独占一行。
//练习 10.33
#include
#include
#include
#include
using namespace std;
int main(int argc, char *argv[])
{
if (argc != 4)
{
cout << "用法:exercise.exe in_file out_file out file" << endl;
return -1;
}
ifstream in(argv[1]);
if (!in)
{
cout << "打开输入文件失败!" << endl;
return -1;
}
ofstream out1(argv[2]);
if (!out1)
{
cout << "打开输出文件1失败!" << endl;
return -1;
}
ofstream out2(argv[3]);
if (!out2)
{
cout << "打开输出文件2失败!" << endl;
return -1;
}
//创建流迭代器从文件读入整数
istream_iterator in_iter(in);
//尾后迭代器
istream_iterator eof;
//第一个输出文件一空格间隔整数
ostream_iterator out_iter1(out1, " ");
//第二个输出文件以换行间隔整数
ostream_iterator out_iter2(out2, "\n");
while (in_iter != eof)
{
if (*in_iter & 1)
{
*out_iter1++ = *in_iter; //这里的*和++没有什么实际意义,但是为了便于理解,还是写上。
}
else
{
*out_iter2++ = *in_iter;
}
++in_iter;
}
system("pause");
return 0;
}
练习 10.34:使用reverse_iterator 逆序打印一个vector。
//练习 10.34
#include
#include
//#include
using namespace std;
int main()
{
vector ivec{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (auto r_iter = ivec.crbegin(); r_iter != ivec.crend(); ++r_iter)
{
cout << *r_iter << " ";
}
cout << endl;
system("pause");
return 0;
}
练习 10.35:使用普通迭代器逆序打印一个vector。
//练习 10.35
#include
#include
#include
using namespace std;
int main()
{
vector ivec{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (auto iter = ivec.end(); iter != ivec.begin(); )
{
cout << *(--iter) << " ";
}
cout << endl;
system("pause");
return 0;
}
练习 10.36:使用find 在一个int 的list 中查找最后一个值为0 的元素。
//练习 10.36
#include
#include
#include
using namespace std;
//list是链表,元素不是连续存储的,迭代器不支持算术运算。
int main()
{
list ilist{ 0, 1, 2, 0, 3, 4, 5, 0, 6 };
auto last_z = find(ilist.rbegin(), ilist.rend(), 0);
//将迭代器向链表头方向推进一个位置
//转换为普通迭代器时,将回到最后一个0的位置
//反向迭代器在转向普通迭代器的时候,会向末尾移动一个位置。
last_z++;
int p = 1; //用p来存储最后一个0出现的位置。
//用base将last_z转换为普通迭代器
//从链表头开始遍历,计数最后一个0的编号
for (auto iter = ilist.begin(); iter != last_z.base(); iter++, p++);
if (p >= ilist.size())
{
cout << "容器中没有0。" << endl;
}
else
{
cout << "最后一个0在第 " << p << "个位置" << endl;
}
system("pause");
return 0;
}
练习 10.37:给定一个包含10 个元素的vector,将位置3 到7 之间的元素按逆序拷贝到一个list 中。
//练习 10.37
#include
#include
#include
#include
#include
using namespace std;
int main(int argc, char *argv[])
{
ostream_iterator out_iter(cout, " ");
vector ivec{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
//用流迭代器和copy输出int序列
copy(ivec.begin(), ivec.end(), out_iter);
cout << endl;
list ilist;
//将vi[2],也就是第3个元素的位置转换为反向迭代器
vector::reverse_iterator r_end(ivec.begin() + 2);
//将vi[7],也就是第8个元素的位置转换为反向迭代器
vector::reverse_iterator r_begin(ivec.begin() + 7);
//用反向迭代器将元素逆序拷贝至list
copy(r_begin, r_end, back_inserter(ilist));
//输出元素
copy(ilist.begin(), ilist.end(), out_iter);
cout << endl;
system("pause");
return 0;
}
练习 10.38:列出5 个迭代器类别,以及每类迭代器所支持的操作。
答:
输入迭代器:只读,不写;单遍扫描,只能递增;还支持相等性判定运算符(==、!=)、解引用运算符(*)和箭头运算符(->)。
输出迭代器:只写,不读;单遍扫描,只能递增,支持解引用运算符。
前向迭代器:可读写;多遍扫描,只能递增,支持所有输入、输出迭代器的操作。
双向迭代器:可读写;多遍扫描,可递增递减,支持所有前向迭代器操作。
随机访问迭代器:可读写,多遍扫描,支持全部迭代器运算。
练习 10.39:list 上的迭代器属于哪类?vector呢?
答:list上是双向迭代器,vector上是随机访问迭代器。
练习 10.40:你认为copy 要求哪类迭代器? reverse 和unique呢?
答:copy要求前两个参数至少是输入迭代器,表示一个输入范围。它读取这个范围中的元素,写入到第三个参数表示的输出序列中,因此第三个参数至少是输出迭代器。
reverse要反向处理序列,因此它要求两个参数至少是双向迭代器。
unique顺序扫描元素,覆盖重复元素,因此要求两个参数至少是前向迭代期,“至少”意味着能力更强的迭代器是可接受的。
练习 10.41:仅根据算法和参数的名字,描述下面每个标准库算法执行什么操作:
replace(beg, end, old_val, new_val);
//将范围[beg,end)间值等于old_val的元素替换为new_val。
replace_if(beg, end, pred, new_val);
//将范围[beg,end)间满足谓词pred的元素替换为new_val。
replace_copy(beg, end, dest, old_val, new_val);
//将范围[beg,end)间元素拷贝到目的序列dest中,将其中值等于old_val的元素替换为new_val。
replace_copy_if(beg, end, dest, pred, new_val);
//将范围[beg,end)间的元素拷贝到目的序列dest中,将其中满足谓词pred的元素替换为new_val。
练习 10.42:使用list代替vector 重新实现10.2.3 节(第343 页)中的去除重复单词的程序。
//练习 10.42
#include
#include
#include
#include
using namespace std;
inline void output_words(list &words)
{
for (auto & r : words)
cout << r << " ";
cout << endl;
}
//list直接调用成员函数,而不是使用通用版本。
void elimDups(list &slst)
{
output_words(slst);
//按字典序排序,以便查找重复单词
slst.sort();
output_words(slst);
//调用erase删除同一个值的连续拷贝
slst.unique();
output_words(slst);
}
int main()
{
list slst{ "the", "quick", "red", "fox", "jumps", "over", "the", "slow", "red", "turtle" };
elimDups(slst);
system("pause");
return 0;
}