从这一章开始,不写知识点了,写点课后习题的答案吧。
练习10.1 头文件algorithm中定义了一个名为count的函数,它类似find,接受一对迭代器和一个值作为参数。count返回给定值在序列中出现的次数。编写程序,读取int序列存入vector中,打印有多少个元素的值等于给定值。
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
using std::cin;
using std::cout;
using std::endl;
using std::vector;
using std::ifstream;
using std::cout;
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if(!in){
cout<<"Open input file failed."<<endl;
exit(1);
}
vector<int>vi;
int val;
while(in>>val)
vi.push_back(val);
cout<<"Please input the number you want find: ";
cin>>val;
cout<<"There are(is) "<<count(vi.begin(), vi.end(), val)<<" "<<val<<" int the vector."<<endl;
return 0;
}
main函数用了命令行参数,可以自己改成不使用命令行参数的。
练习10.2 重做上一题,但读取string序列存入list中。
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <list>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::ifstream;
using std::list;
using std::cout;
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if(!in){
cout<<"Open input file failed."<<endl;
exit(1);
}
list<string> ls;
string word;
while(in>>word)
ls.push_back(word);
cout<<"Please input the string you want find: ";
cin>>word;
cout<<"There are(is) "<<count(ls.begin(), ls.end(), word)<<" "<<word<<" int the list."<<endl;
return 0;
}
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
using std::cin;
using std::cout;
using std::endl;
using std::vector;
using std::ifstream;
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if(!in){
cout<<"Open input file failed."<<endl;
exit(1);
}
int ival;
vector<int> ivec;
while(in>>ival)
ivec.push_back(ival);
cout<<"Sum of vector is "<<accumulate(ivec.begin(), ivec.end(), 0)<<endl;
return 0;
}
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.
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
using std::vector;
using std::cin;
using std::cout;
using std::endl;
using std::ifstream;
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if(!in){
cout<<"Open input file failed."<<endl;
exit(1);
}
int val;
vector<int> vec;
while(in>>val){
vec.push_back(val);
cout<<val<<" ";
}
cout<<endl;
fill_n(vec.begin(), vec.end(), 0);
for(auto i: vec)
cout<<i<<" ";
cout<<endl;
return 0;
}
练习10.7 下面程序是否有错误?如果有,请改正。
(a) vector<int> vec; list<int> lst; int i;
while(cin>>i)
lst.push_back(i);
copy(lst.cbegin(), lst.cend(), vec.begin());
(b) vector<int> 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的内容。
#include <iostream>
using std::cin;
using std::endl;
using std::cout;
#include <vector>
using std::vector;
#include <string>
using std::string;
#include <fstream>
using std::ifstream;
#include <algorithm>
inline void output_words(vector<string> &words)
{
for(auto iter=words.begin(); iter!=words.end(); ++iter)
cout<<*iter<<" ";
cout<<endl;
}
void elimDups(vector<string> &words)
{
output_words(words);
sort(words.begin(), words.end());
output_words(words);
auto end_unique=unique(words.begin(), words.end());
output_words(words);
words.erase(end_unique, words.end());
output_words(words);
}
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if(!in){
cout<<"Open input file failed."<<endl;
exit(1);
}
string word;
vector<string> vec;
while(in>>word)
vec.push_back(word);
elimDups(vec);
return 0;
}
练习10.10 你认为算法不改变容器大小的原因是什么?
泛型算法的一大优点是“泛型”,也就是一个算法可用于多种不同的数据结构,算法与所操作的数据结构分离。要做到算法与数据结构分离,重要的技术手段就是使用迭代器作为两者的桥梁。算法从不操作具体的容器,从而也就不存在与特定容器绑定,不适用于其他容器的问题。算法只操作迭代器,由迭代器真正实现对容器的访问。不同容器实现自己特定的迭代器,算法操作不同的迭代器就实现了对不同容器的访问。
因此,并不是算法应该改变或不改变容器的问题。为了实现与数据结构的分离,为了实现通用性,算法根本就不该知道容器的存在。算法访问数据的唯一通道是迭代器。是否改变容器大小,完全是迭代器的选择和责任。
练习10.11 编写程序,使用stable_sort和isShorter将传递给你的elimDups版本的vector排序。打印vector的内容,验证你程序的正确性。
#include <iostream>
using std::cin;
using std::endl;
using std::cout;
#include <vector>
using std::vector;
#include <string>
using std::string;
#include <fstream>
using std::ifstream;
#include <algorithm>
inline void output_words(vector<string> &words)
{
for(auto iter=words.begin(); iter!=words.end(); ++iter)
cout<<*iter<<" ";
cout<<endl;
}
bool isShorter(const string &s1, const string &s2)
{
return s1.size()<s2.size();
}
void elimDups(vector<string> &words)
{
output_words(words);
sort(words.begin(), words.end());
output_words(words);
auto end_unique=unique(words.begin(), words.end());
output_words(words);
words.erase(end_unique, words.end());
output_words(words);
stable_sort(words.begin(), words.end(), isShorter);
output_words(words);
}
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if(!in){
cout<<"Open input file failed."<<endl;
exit(1);
}
string word;
vector<string> vec;
while(in>>word)
vec.push_back(word);
elimDups(vec);
return 0;
}
练习10.13:标准库定义了名为partition的算法,它接受一个谓词,对容器内容进行划分,是得为此为true的值会排在容器的前半部分,而使谓词为false的值会排在后半部分。算法返回一个迭代器,指向最后一个使谓词为true的元素之后的位置。编写函数,接受一个string,返回一个bool值,指出string是否有5个或更多字符。使用此函数划分words。打印出长度大于等于5的元素。
#include <string>
using std::string;
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <vector>
using std::vector;
#include <algorithm>
#include <fstream>
using std::ifstream;
inline void output_words(vector<string>::iterator beg, vector<string>::iterator end)
{
for(auto iter=beg; iter!=end; ++iter)
cout<<*iter<<" ";
cout<<endl;
}
bool five_or_more(const string &s)
{
return s.size()>=5;
}
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if(!in){
cout<<"Open input file failed."<<endl;
exit(1);
}
string word;
vector<string> vec;
while(in>>word)
vec.push_back(word);
auto iter=partition(vec.begin(),vec.end(),five_or_more);
output_words(vec.begin(),iter);
cout<<endl;
return 0;
}
练习10.14:编写一个lambda,接受两个int,返回它们的和。
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int main(int argc, char *argv[])
{
auto sum=[](int a, int b){return a+b;};
cout<<sum(1,1)<<endl;
return 0;
}
练习10.15:编写一个lambda,捕获它所在函数的int,并接受一个int参数。lambda应该返回捕获的int和int参数的和。
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
void add(int a)
{
auto sum=[a](int b){return a+b;};
cout<<sum(1)<<endl;
}
int main(int argc, char *argv[])
{
add(1);
add(2);
return 0;
}
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <vector>
using std::vector;
#include <string>
using std::string;
#include <algorithm>
#include <fstream>
using std::ifstream;
string make_plural(size_t ctr, const string &word, const string &ending)
{
return (ctr>1)? word + ending: word;
}
void elimdups(vector<string> &words)
{
sort(words.begin(), words.end());
auto end_unique=unique(words.begin(), words.end());
words.erase(end_unique, words.end());
}
void biggies(vector<string> &words, vector<string>::size_type sz)
{
elimdups(words); //将words按字典序排序,删除重复词
// 按长度排序,长度相同的单词维持字典序
stable_sort(words.begin(), words.end(), [](const string &a, const string &b){return a.size()<b.size();});
// 获取一个迭代器,指向第一个满足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;
exit(1);
}
string str;
vector<string> vec;
while(in>>str)
vec.push_back(str);
biggies(vec, 5);
return 0;
}
练习10.18:重写biggies,用partition代替find_if。我们在10.3.1节练习10.13中介绍了partition算法
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <vector>
using std::vector;
#include <string>
using std::string;
#include <algorithm>
#include <fstream>
using std::ifstream;
string make_plural(size_t ctr, const string &word, const string &ending)
{
return (ctr>1)? word + ending: word;
}
void elimdups(vector<string> &words)
{
sort(words.begin(), words.end());
auto end_unique=unique(words.begin(), words.end());
words.erase(end_unique, words.end());
}
void biggies(vector<string> &words, vector<string>::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;
exit(1);
}
string str;
vector<string> vec;
while(in>>str)
vec.push_back(str);
biggies(vec, 5);
return 0;
}
练习10.19:用stable_partition 重写前一题的程序,与stable_sort类似,在划分后的序列中维持原有元素的顺序。
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <vector>
using std::vector;
#include <string>
using std::string;
#include <algorithm>
#include <fstream>
using std::ifstream;
string make_plural(size_t ctr, const string &word, const string &ending)
{
return (ctr>1)? word + ending: word;
}
void elimdups(vector<string> &words)
{
sort(words.begin(), words.end());
auto end_unique=unique(words.begin(), words.end());
words.erase(end_unique, words.end());
}
void biggies(vector<string> &words, vector<string>::size_type sz)
{
elimdups(words); //将words按字典序排序,删除重复词
// 获取一个迭代器,指向最后一个满足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;
exit(1);
}
string str;
vector<string> vec;
while(in>>str)
vec.push_back(str);
biggies(vec, 5);
return 0;
}
练习10.20:标准库定义了一个名为count_if的算法。类似find_if,此函数接受一对迭代器,表示一个输入范围,还接受一个谓词,会对输入范围中每个元素执行。count_if返回一个计数值,表示谓词有多少次为真。使用count_if重写我们程序中统计有多少单词长度超过6的部分。
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <vector>
using std::vector;
#include <algorithm>
using std::count_if;
#include <string>
using std::string;
#include <fstream>
using std::ifstream;
string make_plural(size_t ctr, const string &word, const string &ending)
{
return (ctr>1) ? word + ending : word;
}
inline void output_words(vector<string> &words)
{
for(auto iter=words.begin(); iter!=words.end(); ++iter)
cout<<*iter<<" ";
cout<<endl;
}
void biggies(vector<string> &words, vector<string>::size_type sz)
{
output_words(words);
auto bc=count_if(words.begin(), words.end(), [sz](const string &a){return a.size()>=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<<"Open input file failed."<<endl;
exit(1);
}
string str;
vector<string> vec;
while(cin>>str)
vec.push_back(str);
biggies(vec,6);
return 0;
}
练习10.21:编写一个lambda,捕获一个局部int变量,并递减变量值,直至它变为0.一旦变为0,再调用lambda应该不再递减变量。lambda应该返回一个bool值,指出捕获的变量是否为0.
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <algorithm>
void mutable_lambda(void)
{
int i=5;
auto f=[i]() mutable->bool {if(i>0) {--i; return false;} else return true;};
for(int j=0; j<6; ++j)
cout<<f()<<" ";
cout<<endl;
}
int main(int argc, char *argv[])
{
mutable_lambda();
return 0;
}
练习10.22:重写统计长度小于等于6的单词数量的程序,使用函数代替lambda。
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <algorithm>
#include <functional>
using std::cin;
using std::cout;
using std::endl;
using std::vector;
using std::string;
using std::ifstream;
using std::bind;
using std::placeholders::_1;
string make_plural(size_t ctr, const string &word, const string &ending)
{
return (ctr>1)? word + ending: word;
}
inline void output_words(vector<string> &words)
{
for(auto iter=words.begin(); iter!=words.end(); ++iter)
cout<<*iter<<" ";
cout<<endl;
}
bool check_size(const string &s,string::size_type sz)
{
return s.size()>=sz;
}
auto check6=bind(check_size, _1, 6);
void biggies(vector<string> &words, vector<string>::size_type sz)
{
output_words(words);
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;
cout<<endl;
}
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if(!in){
cout<<"Open input file failed."<<endl;
exit(1);
}
string str;
vector<string> vec;
while(in>>str)
vec.push_back(str);
biggies(vec, 6);
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长度的值。
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <string>
using std::string;
#include <vector>
using std::vector;
#include <functional>
using std::placeholders::_1;
#include <algorithm>
bool check_size(const string &s, int sz)
{
return s.size()<sz;
}
void biggies(vector<string> &vc, const string &s)
{
// 查找第一个大于等于s长度的数值
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<int> vc={1,2,3,4,5,6,7,8,9};
biggies(vc,"hello");
biggies(vc,"everyone");
biggies(vc,"!");
return 0;
}
练习10.25:在10.3.2节的练习中,编写了一个使用partition的biggies版本。使用check_size和bind重写此函数。
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <vector>
using std::vector;
#include <string>
using std::string;
#include <algorithm>
#include <functional>
using std::placeholders::_1;
#include <fstream>
using std::ifstream;
bool check_size(const string &s, string::size_type sz)
{
return s.size() >= sz;
}
void elimDups(vector<string> &words)
{
sort(words.begin(), words.end());
auto end_unique=unique(words.begin(), words.end());
words.erase(end_unique, words.end());
}
string make_plural(size_t ctr, const string &word, const string &ending)
{
return (ctr > 1) ? word + ending : word;
}
void biggies(vector<string> &words, vector<string>::size_type sz)
{
elimDups(words);
for_each(words.begin(), words.end(), [](const string &s){cout << s << " "; });
cout<<endl;
auto wc = partition(words.begin(), words.end(), bind(check_size, _1, 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;
exit(1);
}
string word;
vector<string> vec;
while(in>>word)
vec.push_back(word);
biggies(vec,6);
return 0;
}
练习10.26:解释三种插入迭代器的不同之处。
三者的差异在于如何向容器插入元素:back_inserter调用push_back,front_inserter 调用push_front,inserter则调用inserter。这决定了它们插入元素位置的不同。back_inserter总是插入到容器尾元素之后,front_inserter 总是插入到元素首元素之前,而inserter则是插入到给定位置之前。
练习10.27:除了unique之外,标准库还定义了名为unique_copy的函数,它接受第三个迭代器,表示拷贝不重复元素的目的位置。编写一个程序,使用unique_copy将一个vector中不重复的元素拷贝到一个初始为空的list中。
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <vector>
using std::vector;
#include <algorithm>
#include <list>
using std::list;
#include <iterator>
using std::inserter;
int main(int argc, char *argv[])
{
vector<int> vi={1,2,2,3,4,5,5,6};
list<int> li;
unique_copy(vi.begin(), vi.end(), back_inserter(li));
for_each(li.begin(), li.end(), [](const int &i){cout << i << " "; });
cout<<endl;
return 0;
}
练习10.28:一个vector中保存1到9共9个值,将其拷贝到三个其他容器中。分别使用inserter、back_inserter 和front_inserter将元素添加到三个容器中。对每种 inserter,估计输出序列是怎样的,运行程序验证你的估计是否正确。
#include <iostream>
using std::cout;
using std::endl;
#include <vector>
using std::vector;
#include <list>
using std::list;
#include <algorithm>
#include <iterator>
using std::inserter;
int main(int argc, char *argv[])
{
vector<int> vec={1,2,3,4,5,6,7,8,9};
list<int> lst1,lst2,lst3;
unique_copy(vec.begin(), vec.end(), front_inserter(lst1));
unique_copy(vec.begin(), vec.end(), back_inserter(lst2));
unique_copy(vec.begin(), vec.end(), inserter(lst3,lst3.begin()));
for_each(lst1.begin(), lst1.end(), [](const int &i){cout<<i<<" ";});
cout<<endl;
for_each(lst2.begin(), lst2.end(), [](const int &i){cout<<i<<" ";});
cout<<endl;
for_each(lst3.begin(), lst3.end(), [](const int &i){cout<<i<<" ";});
cout<<endl;
}
练习10.29:编写程序,使用流迭代器读取一个文本文件,存入一个vector中的string里。
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <fstream>
using std::ifstream;
#include <vector>
using std::vector;
#include <string>
using std::string;
#include <iterator>
using std::istream_iterator;
using std::ostream_iterator;
#include <algorithm>
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if(!in){
cout<<"Open input file failed."<<endl;
exit(1);
}
// 创建流迭代器从文件读取字符串
istream_iterator<string> str_it(in);
// 尾后迭代器
istream_iterator<string> eof;
vector<string> svec;
while(str_it!=eof)
svec.push_back(*str_it++);
ostream_iterator<string> out_iter(cout," ");
copy(svec.begin(),svec.end(),out_iter);
return 0;
}
练习10.30:使用流迭代器、sort和copy从标准输入读取一个整数序列,将其排序,并将结果写到标准输出。
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <vector>
using std::vector;
#include <algorithm>
#include <iterator>
using std::istream_iterator;
using std::ostream_iterator;
int main(int argc, char *argv[])
{
istream_iterator<int> int_it(cin), eof;
vector<int> vec;
while(int_it!=eof)
vec.push_back(*int_it++);
sort(vec.begin(), vec.end());
ostream_iterator<int> out_iter(cout, " ");
copy(vec.begin(), vec.end(), out_iter);
return 0;
}
</pre>练习10.31:修改前一题的程序,使其只打印不重复元素。你的程序应使用unique_copy。<p></p><p><span style="font-size:14px"></span></p><pre name="code" class="cpp">#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <vector>
using std::vector;
#include <algorithm>
#include <iterator>
using std::istream_iterator;
using std::ostream_iterator;
int main(int argc, char *argv[])
{
istream_iterator<int> int_it(cin), eof;
vector<int> vec;
while(int_it!=eof)
vec.push_back(*int_it++);
sort(vec.begin(), vec.end());
ostream_iterator<int> out_iter(cout, " ");
unique_copy(vec.begin(), vec.end(), out_iter);
return 0;
}
练习10.33:编写程序,接受三个参数:一个输入文件和两个输出文件的文件名。输入文件保存的应该是整数。使用istream_iterator读取输入文件。使用ostream_iterator将奇数写入第一个输出文件,每个值之后都跟一个空格。将偶数写入第二个输出文件,每个值独占一行。
#include <iostream>
using std::endl;
using std::cout;
#include <iterator>
using std::istream_iterator;
using std::ostream_iterator;
#include <string>
using std::string;
#include <algorithm>
#include <fstream>
using std::ifstream;
using std::ofstream;
int main(int argc, char *argv[])
{
if(argc!=4){
cout<<"用法: exercise.exe in_file out_file1 out_file2"<<endl;
return -1;
}
ifstream in(argv[1]);
if(!in){
cout<<"Open input file failed."<<endl;
exit(1);
}
ofstream out1(argv[2]);
if(!out1){
cout<<"Open output file 1 failed."<<endl;
exit(1);
}
ofstream out2(argv[3]);
if(!out2){
cout<<"Open output file 2 failed."<<endl;
exit(1);
}
// 创建流迭代器从文件读入整数
istream_iterator<int> in_iter(in);
// 尾后迭代器
istream_iterator<int> eof;
// 第一个输出文件以空格间隔整数
ostream_iterator<int> out_iter1(out1, " ");
// 第二个输出文件一换行间隔整数
ostream_iterator<int> out_iter2(out2, "\n");
while(in_iter!=eof){
if(*in_iter%1) //奇数写入第一个文件
*out_iter1++= *in_iter;
else //偶数写入第二个文件
*out_iter2++= *in_iter;
++in_iter;
}
return 0;
}
练习10.34:使用reserve_iterator逆序打印一个vector。
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <vector>
using std::vector;
#include <iterator>
using std::ostream_iterator;
#include <algorithm>
#include <fstream>
using std::ifstream;
int main(int argc, char *argv[])
{
if(argc!=2){
cout<<"用法:exercise.exe in_file"<<endl;
return -1;
}
ifstream in(argv[1]);
if(!in){
cout<<"Open input file failed."<<endl;
exit(1);
}
int val;
vector<int> vec;
while(in>>val) //从文件中读取整数
vec.push_back(val);
ostream_iterator<int> out_it(cout, " ");
copy(vec.rbegin(),vec.rend(),out_it);
return 0;
}
练习10.35:使用普通迭代器逆序打印一个vector。
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <vector>
using std::vector;
#include <iterator>
#include <algorithm>
#include <fstream>
using std::ifstream;
int main(int argc, char *argv[])
{
if(argc!=2){
cout<<"用法:exercise.exe in_file"<<endl;
return -1;
}
ifstream in(argv[1]);
if(!in){
cout<<"Open input file failed."<<endl;
exit(1);
}
int val;
vector<int> vec;
while(cin>>val)
vec.push_back(val);
for(vector<int>::iterator it=vec.end(); it!=vec.begin();)
cout<<*(--it)<<" ";
cout<<endl;
return 0;
}
练习10.36:使用find在一个int的list中查找最后一个值为0的元素。
#include <iostream>
#include <iterator>
#include <algorithm>
#include <list>
using namespace std;
int main(int argc, char *argv[])
{
list<int> li = { 1, 1, 2, 3, 5, 8, 0, 13, 13, 26, 0, 39 };
// 利用反向迭代器查找最后一个0
auto last_z = find(li.rbegin(), li.rend(), 0);
// 将迭代器向链表头方向推进一个位置
// 转换为普通迭代器时,将回到最后一个0的位置
++last_z;
int p=1;
// 用base将last_z转换为普通迭代器
// 从链表头开始遍历,计数最后一个0的编号
for(auto iter=li.begin(); iter!=last_z.base(); ++iter,++p);
if(p>=li.size()) //未找到0
cout<<"容器中没有0"<<endl;
else
cout<<"最后一个0在第"<<p<<"个位置"<<endl;
return 0;
}
练习10.37:给定一个包含10个元素的vector,将位置3到7之间的元素按逆序拷贝到一个list中。
#include <iostream>
#include <algorithm>
#include <vector>
#include <list>
#include <iterator>
using namespace std;
int main(int argc, char *argv[])
{
vector<int> vi = { 0, 1 ,2, 3, 4, 5, 6, 7, 8, 9};
ostream_iterator<int> out_iter(cout, " ");
// 用流迭代器和copy输出int序列
copy(vi.begin(), vi.end(), out_iter);
cout << endl;
list<int> li;
//将vi[2],也就是第3个元素的位置转换为反向迭代器
vector<int>::reverse_iterator re(vi.begin()+2);
// 将vi[7],也就是第8个元素的位置转换为反向迭代器
vector<int>::reverse_iterator rb(vi.begin()+7);
// 用反向迭代器将元素逆序拷贝到list
copy(rb, re, back_inserter(li));
copy(li.begin(), li.end(), out_iter);
cout<<endl;
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);
replace_if(beg, end, pred, old_val, new_val);
replace_copy(beg, end, dest, old_val, new_val);
replace_copy_if(beg, end, dest, pred, new_val);
1.将范围[beg, end)间值等于old_val的元素替换为new_val;
2.将范围[beg, end)间满足谓词pred的元素替换为new_val;
3.将范围[beg, end)间的元素拷贝到目的序列dest中,将其中值等于old_val的元素替换为new_val;
4.将范围[beg, end)间的元素拷贝到目的序列dest中,将其中满足谓词pred的元素替换为new_val;
练习10.42:使用list代替vector重新实现10.2.3节中的去除重复单词的程序。
#include <iostream>
#include <string>
#include <list>
#include <algorithm>
#include <iterator>
#include <fstream>
using namespace std;
inline void output_words(list<string> &words)
{
for(auto iter=words.begin(); iter!=words.end(); ++iter)
cout<<*iter<<" ";
cout<<endl;
}
void elimDups(list<string> &words)
{
output_words(words);
words.sort();
output_words(words);
words.unique();
output_words(words);
}
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if(!in){
cout<<"Open input file failed."<<endl;
exit(1);
}
list<string> words;
string word;
while(in>>word)
words.push_back(word);
elimDups(words);
return 0;
}