C++primer第五版第十章学习笔记

来源:互联网 发布:韩略村伏击战知乎 编辑:程序博客网 时间:2024/05/20 20:21

从这一章开始,不写知识点了,写点课后习题的答案吧。

练习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;}


练习10.3 使用accumulate求一个vector<int>中的元素之和。

#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;}


练习10.4 假定v是一个vector<double>,那么调用accumulate( v.cbegin(), v.cend(), 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;}


练习10.16:使用lambda编写你自己版本的biggies.

#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 };// 利用反向迭代器查找最后一个0auto 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())   //未找到0cout<<"容器中没有0"<<endl;elsecout<<"最后一个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;}


1 0
原创粉丝点击