从这一章开始,不写知识点了,写点课后习题的答案吧。
练习10.1 头文件algorithm中定义了一个名为count的函数,它类似find,接受一对迭代器和一个值作为参数。count返回给定值在序列中出现的次数。编写程序,读取int序列存入vector中,打印有多少个元素的值等于给定值。
#include
#include
#include
#include
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."<vi;
int val;
while(in>>val)
vi.push_back(val);
cout<<"Please input the number you want find: ";
cin>>val;
cout<<"There are(is) "<
main函数用了命令行参数,可以自己改成不使用命令行参数的。
练习10.2 重做上一题,但读取string序列存入list中。
#include
#include
#include
#include
#include
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."< ls;
string word;
while(in>>word)
ls.push_back(word);
cout<<"Please input the string you want find: ";
cin>>word;
cout<<"There are(is) "<
#include
#include
#include
#include
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."< ivec;
while(in>>ival)
ivec.push_back(ival);
cout<<"Sum of vector is "<
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
#include
#include
#include
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."< vec;
while(in>>val){
vec.push_back(val);
cout<
(a) vector vec; list lst; int i;
while(cin>>i)
lst.push_back(i);
copy(lst.cbegin(), lst.cend(), 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的内容。
#include
using std::cin;
using std::endl;
using std::cout;
#include
using std::vector;
#include
using std::string;
#include
using std::ifstream;
#include
inline void output_words(vector &words)
{
for(auto iter=words.begin(); iter!=words.end(); ++iter)
cout<<*iter<<" ";
cout< &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."< vec;
while(in>>word)
vec.push_back(word);
elimDups(vec);
return 0;
}
泛型算法的一大优点是“泛型”,也就是一个算法可用于多种不同的数据结构,算法与所操作的数据结构分离。要做到算法与数据结构分离,重要的技术手段就是使用迭代器作为两者的桥梁。算法从不操作具体的容器,从而也就不存在与特定容器绑定,不适用于其他容器的问题。算法只操作迭代器,由迭代器真正实现对容器的访问。不同容器实现自己特定的迭代器,算法操作不同的迭代器就实现了对不同容器的访问。
因此,并不是算法应该改变或不改变容器的问题。为了实现与数据结构的分离,为了实现通用性,算法根本就不该知道容器的存在。算法访问数据的唯一通道是迭代器。是否改变容器大小,完全是迭代器的选择和责任。
练习10.11 编写程序,使用stable_sort和isShorter将传递给你的elimDups版本的vector排序。打印vector的内容,验证你程序的正确性。
#include
using std::cin;
using std::endl;
using std::cout;
#include
using std::vector;
#include
using std::string;
#include
using std::ifstream;
#include
inline void output_words(vector &words)
{
for(auto iter=words.begin(); iter!=words.end(); ++iter)
cout<<*iter<<" ";
cout< &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."< vec;
while(in>>word)
vec.push_back(word);
elimDups(vec);
return 0;
}
#include
using std::string;
#include
using std::cin;
using std::cout;
using std::endl;
#include
using std::vector;
#include
#include
using std::ifstream;
inline void output_words(vector::iterator beg, vector::iterator end)
{
for(auto iter=beg; iter!=end; ++iter)
cout<<*iter<<" ";
cout<=5;
}
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if(!in){
cout<<"Open input file failed."< vec;
while(in>>word)
vec.push_back(word);
auto iter=partition(vec.begin(),vec.end(),five_or_more);
output_words(vec.begin(),iter);
cout<
#include
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<
#include
using std::cin;
using std::cout;
using std::endl;
void add(int a)
{
auto sum=[a](int b){return a+b;};
cout<
#include
using std::cin;
using std::cout;
using std::endl;
#include
using std::vector;
#include
using std::string;
#include
#include
using std::ifstream;
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< vec;
while(in>>str)
vec.push_back(str);
biggies(vec, 5);
return 0;
}
#include
using std::cin;
using std::cout;
using std::endl;
#include
using std::vector;
#include
using std::string;
#include
#include
using std::ifstream;
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< vec;
while(in>>str)
vec.push_back(str);
biggies(vec, 5);
return 0;
}
#include
using std::cin;
using std::cout;
using std::endl;
#include
using std::vector;
#include
using std::string;
#include
#include
using std::ifstream;
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=stable_partition(words.begin(), words.end(), [sz](const string &a){return a.size()>=sz;});
// 计算满足size()>=sz的元素的数目
auto count=wc-words.begin();
cout< vec;
while(in>>str)
vec.push_back(str);
biggies(vec, 5);
return 0;
}
#include
using std::cin;
using std::cout;
using std::endl;
#include
using std::vector;
#include
using std::count_if;
#include
using std::string;
#include
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 &words)
{
for(auto iter=words.begin(); iter!=words.end(); ++iter)
cout<<*iter<<" ";
cout< &words, vector::size_type sz)
{
output_words(words);
auto bc=count_if(words.begin(), words.end(), [sz](const string &a){return a.size()>=sz;});
cout< vec;
while(cin>>str)
vec.push_back(str);
biggies(vec,6);
return 0;
}
#include
using std::cin;
using std::cout;
using std::endl;
#include
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<
#include
#include
#include
#include
#include
#include
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 &words)
{
for(auto iter=words.begin(); iter!=words.end(); ++iter)
cout<<*iter<<" ";
cout<=sz;
}
auto check6=bind(check_size, _1, 6);
void biggies(vector &words, vector::size_type sz)
{
output_words(words);
auto bc=count_if(words.begin(), words.end(), bind(check_size, _1, sz));
cout< 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
using std::cin;
using std::cout;
using std::endl;
#include
using std::string;
#include
using std::vector;
#include
using std::placeholders::_1;
#include
bool check_size(const string &s, int sz)
{
return s.size() &vc, const string &s)
{
// 查找第一个大于等于s长度的数值
auto p=find_if(vc.begin(), vc.end(), bind(check_size, s, _1));
// 打印结果
cout<<"第"< vc={1,2,3,4,5,6,7,8,9};
biggies(vc,"hello");
biggies(vc,"everyone");
biggies(vc,"!");
return 0;
}
#include
using std::cin;
using std::cout;
using std::endl;
#include
using std::vector;
#include
using std::string;
#include
#include
using std::placeholders::_1;
#include
using std::ifstream;
bool check_size(const string &s, string::size_type sz)
{
return s.size() >= sz;
}
void elimDups(vector &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 &words, vector::size_type sz)
{
elimDups(words);
for_each(words.begin(), words.end(), [](const string &s){cout << s << " "; });
cout< vec;
while(in>>word)
vec.push_back(word);
biggies(vec,6);
return 0;
}
三者的差异在于如何向容器插入元素: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
using std::cin;
using std::cout;
using std::endl;
#include
using std::vector;
#include
#include
using std::list;
#include
using std::inserter;
int main(int argc, char *argv[])
{
vector vi={1,2,2,3,4,5,5,6};
list li;
unique_copy(vi.begin(), vi.end(), back_inserter(li));
for_each(li.begin(), li.end(), [](const int &i){cout << i << " "; });
cout<
#include
using std::cout;
using std::endl;
#include
using std::vector;
#include
using std::list;
#include
#include
using std::inserter;
int main(int argc, char *argv[])
{
vector vec={1,2,3,4,5,6,7,8,9};
list 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<
#include
using std::cin;
using std::cout;
using std::endl;
#include
using std::ifstream;
#include
using std::vector;
#include
using std::string;
#include
using std::istream_iterator;
using std::ostream_iterator;
#include
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if(!in){
cout<<"Open input file failed."< str_it(in);
// 尾后迭代器
istream_iterator eof;
vector svec;
while(str_it!=eof)
svec.push_back(*str_it++);
ostream_iterator out_iter(cout," ");
copy(svec.begin(),svec.end(),out_iter);
return 0;
}
#include
using std::cin;
using std::cout;
using std::endl;
#include
using std::vector;
#include
#include
using std::istream_iterator;
using std::ostream_iterator;
int main(int argc, char *argv[])
{
istream_iterator int_it(cin), eof;
vector vec;
while(int_it!=eof)
vec.push_back(*int_it++);
sort(vec.begin(), vec.end());
ostream_iterator out_iter(cout, " ");
copy(vec.begin(), vec.end(), out_iter);
return 0;
}
练习10.31:修改前一题的程序,使其只打印不重复元素。你的程序应使用unique_copy。#includeusing std::cin; using std::cout; using std::endl; #include using std::vector; #include #include using std::istream_iterator; using std::ostream_iterator; int main(int argc, char *argv[]) { istream_iterator int_it(cin), eof; vector vec; while(int_it!=eof) vec.push_back(*int_it++); sort(vec.begin(), vec.end()); ostream_iterator out_iter(cout, " "); unique_copy(vec.begin(), vec.end(), out_iter); return 0; }
#include
using std::endl;
using std::cout;
#include
using std::istream_iterator;
using std::ostream_iterator;
#include
using std::string;
#include
#include
using std::ifstream;
using std::ofstream;
int main(int argc, char *argv[])
{
if(argc!=4){
cout<<"用法: exercise.exe in_file out_file1 out_file2"< 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;
}
return 0;
}
#include
using std::cin;
using std::cout;
using std::endl;
#include
using std::vector;
#include
using std::ostream_iterator;
#include
#include
using std::ifstream;
int main(int argc, char *argv[])
{
if(argc!=2){
cout<<"用法:exercise.exe in_file"< vec;
while(in>>val) //从文件中读取整数
vec.push_back(val);
ostream_iterator out_it(cout, " ");
copy(vec.rbegin(),vec.rend(),out_it);
return 0;
}
#include
using std::cin;
using std::cout;
using std::endl;
#include
using std::vector;
#include
#include
#include
using std::ifstream;
int main(int argc, char *argv[])
{
if(argc!=2){
cout<<"用法:exercise.exe in_file"< vec;
while(cin>>val)
vec.push_back(val);
for(vector::iterator it=vec.end(); it!=vec.begin();)
cout<<*(--it)<<" ";
cout<
#include
#include
#include
#include
using namespace std;
int main(int argc, char *argv[])
{
list 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"<
#include
#include
#include
#include
#include
using namespace std;
int main(int argc, char *argv[])
{
vector vi = { 0, 1 ,2, 3, 4, 5, 6, 7, 8, 9};
ostream_iterator out_iter(cout, " ");
// 用流迭代器和copy输出int序列
copy(vi.begin(), vi.end(), out_iter);
cout << endl;
list li;
//将vi[2],也就是第3个元素的位置转换为反向迭代器
vector::reverse_iterator re(vi.begin()+2);
// 将vi[7],也就是第8个元素的位置转换为反向迭代器
vector::reverse_iterator rb(vi.begin()+7);
// 用反向迭代器将元素逆序拷贝到list
copy(rb, re, back_inserter(li));
copy(li.begin(), li.end(), out_iter);
cout<
输入迭代器:只读,不写;单遍扫描,只能递增;还支持相等性判定运算符(==、!=)、解引用运算符(*)和箭头运算符(->)。
输出迭代器:只写,不读;单遍扫描,只能递增,支持解引用运算符。
前向迭代器:可读写;多遍扫描,只能递增,支持所有输入、输出迭代器的操作。
双向迭代器:可读写;多遍扫描,可递增递减,支持所有前向迭代器操作。
随机访问迭代器:可读写,多遍扫描,支持全部迭代器运算。
练习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
#include
#include
#include
#include
#include
using namespace std;
inline void output_words(list &words)
{
for(auto iter=words.begin(); iter!=words.end(); ++iter)
cout<<*iter<<" ";
cout< &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."< words;
string word;
while(in>>word)
words.push_back(word);
elimDups(words);
return 0;
}