练习 10.1 头文件algorthm中定义了一个名为count的函数,它类似于find,接受一对迭代器和一个值作为参数。count返回定值出现的次数。编写程序,读取int序列存入vector中,打印有多少个元素值等于定值。
vector<int> ivec;
int i ;
while(cin >> i)
ivec.push_back(i);
int n1 = count(ivec.begin(),ivec.end(),1);
cout<< n1;
练习 10.2 重做上一题,但读取string序列存入list中。
vector<string> ivec;
string i ;
while(cin >> i)
ivec.push_back(i);
int n1 = count(ivec.begin(),ivec.end(),"is");
cout<< n1;
练习10.3:用accumulate求一个vector<int>中的元素之和。
vector<int> ivec{1,2,3,4,5,6,7,8,9};
cout<<accumulate(ivec.cbegin(),ivec.cend(),0);
练习10.4 假定 v 是一个vector,那么调用 accumulate(v.cbegin(),v.cend(),0) 有何错误(如果存在的话)?
vector<double> ivec{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9};
cout<<accumulate(ivec.cbegin(),ivec.cend(),0);
默认为int操作,计算精度降低。
练习10.5 在本节对名册(roster)调用equal 的例子中,如果两个名册中保存的都是C风格字符串而不是string,会发生什么?
如果是c风格的话,equal会比较指向的地址,而不是字符串的值。
练习10.6 编写程序,使用full_n将一个序列中的int值都设置为0。
vector<int> ivec={123,13,5,8,123,0};
fill_n(ivec.begin() , ivec.size(),0);
for (auto i: ivec) {
cout<<i<<' ';
}
练习10.7 下面程序是否有错误?如果有,请改正。
a) vector<int> vec; list<int> lst; int i;
while(cin>>i)
lst.push_back(i);
copy(lst.cbengin(),lst.cend(),vec.begin());
b) vector<int> vec;
vec.reserve(10);
fill_n(vec.begin(), 10 , 0);
对于a)来说,vec是空的,而算法不会给他开辟空间,算法永远不会改变底层的大小,所以这个地方要用back_inserter,插入迭代器来给vec赋值。
vector<int> vec; list<int> lst = {1,2,3,4}; int i;
// while(cin>>i)
// lst.push_back(i);
copy(lst.begin(),lst.end(), back_inserter(vec));
for (auto i: vec) {
cout << i << ' ';
}
对于b)来说reserve之后vec的大小还是0;所以将reserve改为resize,或者使用插入迭代器。
vector<int> vec;
vec.resize(10);
fill_n(vec.begin(), 10 , 0);
vector<int> vec;
vec.resize(10);
fill_n(back_inserter(vec), 10 , 0);
练习10.8 本节提到过,标准库算法不会改变它们所操作的容器的大小。为什么使用back_inserter不会使这一断言失效?
inserter不是隶属于algorithm,而是属于iterator头文件,所以这一断言没有失效,并且back_inserter这个迭代器配合algorithm头文件的里的算法有更灵活的使用。
练习10.9 实现你自己的elimDups。测试你的程序,分别在读取输入后、调用unique后以及调用erase后打印vector的内容。
void elimDups(vector<string> &words){
for (auto s: words) {
cout<<s<<' ';
}
cout<<endl;
sort(words.begin(),words.end());
vector<string>::iterator end_unique = unique(words.begin(),words.end());
for (auto s: words) {
cout<<s<<' ';
}
cout<<endl;
words.erase(end_unique,words.end());
}
练习10.10 你认为算法不改变容器大小的原因是什么?
@Mooophy:
这种设计的目的是将算法和成员函数提供的操作分开。
@pezy:
因为库算法在迭代器上运行,而不是在容器上运行。因此,算法不能(直接)添加或删除元素。
练习10.11 编写程序,使用stable_sort和isShort将传递给你的elimDups版本的vector排序。打印vector的内容,验证你的程序的正确性。
#include <iostream>
#include <vector>
#include <list>
#include <deque>
#include <forward_list>
#include <algorithm>
#include <numeric>
using namespace std;
void elimDups(vector<string> &words){
for (auto s: words) {
cout<<s<<' ';
}
cout<<endl;
sort(words.begin(),words.end());
vector<string>::iterator end_unique = unique(words.begin(),words.end());
for (auto s: words) {
cout<<s<<' ';
}
cout<<endl;
words.erase(end_unique,words.end());
}
bool is_short(const string &s1, const string &s2){
return s1.size() < s2.size();
}
int main() {
vector<string> vec = {"a","b","c","d","e","f","g","a","b","d","1234", "1234", "1234", "Hi", "alan", "wang"};
elimDups(vec);
stable_sort(vec.begin(),vec.end(), is_short);
for (auto s: vec) {
cout<<s<<' ';
}
cout<<endl;
return 0;
}
练习10.13 标准库定义了名为partition的算法,它接受一个谓词,对容器内容进行划分,使得谓词为true的值会排在容器的前半部分,而谓词为false的值会排在后半部分。算法返回一个迭代器,指向最后一个使用谓词为true的元素之后的位置。编写函数,接受一个string,返回一个bool值,指出string是否有5个或更多字符。使用此函数划分words。打印出长度大于等于5的元素。
bool no_short(const string &s){
return s.size()>= 5;
}
int main() {
vector<string> vec = {"aaaaa","baaaa","caaa","daaaa","e","f","g","a","b","d","12334", "41234", "ff1234", "Hi", "alan", "wang"};
vector<string>::iterator end_m = partition(vec.begin(),vec.end(), no_short);
for (auto it = vec.begin(); it != end_m ; ++it) {
cout<< *it<<' ';
}
return 0;
}
练习10.14 编写一个lambda,接受两个int,返回它们的和。
int main() {
auto f = [](const int &a, const int &b) -> int{ return a + b;};
cout<<f(1,2);
return 0;
}
练习10.15 编写一个lambda,捕获它所在函数的int,并接受一个int参数。lambda应该返回捕获的int和int参数的和。
void tes(){
int i = 1;
int j = 3;
auto f = [i](const int &a) -> int{return i + a;};
cout<<f(j);
}
练习10.16 使用lambda编写你自己版本的biggies。
void elimDups(vector<string> &words){
for (auto s: words) {
cout<<s<<' ';
}
cout<<endl;
sort(words.begin(),words.end());
vector<string>::iterator end_unique = unique(words.begin(),words.end());
for (auto s: words) {
cout<<s<<' ';
}
cout<<endl;
words.erase(end_unique,words.end());
}
void biggies(vector<string> &s,const int &num){
elimDups(s);
auto start = find_if(s.begin(),s.end(),[num](const string &a){return a.size() >= num;});
while(start != s.cend()){
cout<<*start++<<' ';
}
}
int main() {
vector<string> s = {"123","12345","12345","12345","12359067","1235927846"};
biggies(s,5);
return 0;
}
练习10.18 重写biggies函数,用partition代替find_if。我们在10.3.1节练习10.13中介绍了partition算法。
void biggies(vector<string> &s,const int &num){
elimDups(s);
auto end = partition(s.begin(),s.end(),[num](const string &a){return a.size() >= num;});
auto it = s.begin();
while(it != end){
cout<<*it++<<' ';
}
}
int main() {
vector<string> s = {"123","12345","12345","12345","12359067","1235927846"};
biggies(s,5);
return 0;
}
练习10.19 用stable_partition 重写前一道题的程序,与stable_sort类似,在划分后的序列中维持原有元素的顺序。
void biggies(vector<string> &s,const int &num){
elimDups(s);
auto end = stable_partition(s.begin(),s.end(),[num](const string &a){return a.size() >= num;});
auto it = s.begin();
while(it != end){
cout<<*it++<<' ';
}
}
int main() {
vector<string> s = {"123","12345","12345","12345","12359067","1235927846"};
biggies(s,5);
return 0;
}
练习10.20 标准库定义了一个名为count_if的算法。类似find_if,此函数接受一对迭代器,表示一个输入范围,还接受一个谓词,会对输入范围中的每个元素执行。count_if返回一个计数值,表示谓词有多少为真。使用count_if重写我们程序中统计多少单词长度超过6的部分。
void elimDups(vector<string> &words){
for (auto s: words) {
cout<<s<<' ';
}
cout<<endl;
sort(words.begin(),words.end());
vector<string>::iterator end_unique = unique(words.begin(),words.end());
for (auto s: words) {
cout<<s<<' ';
}
cout<<endl;
words.erase(end_unique,words.end());
}
int main() {
vector<string> s = {"123","12345","12345","12345","12359067","1235927846"};
elimDups(s);
int n = 6;
auto num = count_if(s.begin(),s.end(),[&n](string &s) -> bool { return s.size() > n;});
cout<<num;
return 0;
}
练习10.21 编写一个lambda,捕获一个局部变量int变量,并递减变量值,直至它变为0。一旦变量变为0,再调用lambda应该不再递减变量。lambda应该返回一个bool值,指出捕获的变量是否为0。
int main() {
vector<string> s = {"123","12345","12345","12345","12359067","1235927846"};
int i = 6;
auto temp = [&i] () -> bool { if ((i--) >0) return true ; else return false ; };
while(temp())
cout<<i<<' ';
return 0;
}
练习10.22 重写统计长度小于等于6的单词数量的程序,使用函数代替lambda。
挺简单的就不写了。
练习10.23 bind接受几个参数?
如果函数有n个参数,那么bind有n+1个参数。
练习10.24 给定一个string,使用bind和check_size在一个int的vector中查找第一个大于string长度的值。
using std::cout;
using std::endl;
using std::string;
using std::vector;
using std::find_if;
using std::bind;
using std::size_t;
auto check_size(string const& str, size_t sz)
{
return str.size() < sz;
}
int main()
{
vector<int> vec{ 0, 1, 2, 3, 4, 5, 6, 7 };
string str("123456");
auto result = find_if(vec.begin(), vec.end(), bind(check_size, str, _1));
if (result != vec.cend())
cout << *result << endl;
else
cout << "Not found" << endl;
return 0;
}