10.2、初识泛型算法
1、只读算法
//对vec中的元素求和,和的初值是0,头文件是numeric
int sum = accumulate(vec.cbegin(), vec.cend(), 0);
//将vector中所有的string元素连接起来
string sum = accumulate(v.cbegin(), v.cend(), string(""));
//equal用于确定两个序列是否保存相同的值,第二个序列元素数目至少应该与第一个一样多
equal(roster1.cbegin(), roster1.cend(), roster2.cbegin());
2、写容器元素的算法
//将每个元素重置为0
fill(vec.begin(), vec.end(), 0);
vector<int> vec;
fill_n(vec.begin(), vec.size(), 0);//将所有元素重置为0,不可指定大小,算法不检查写操作
fill_n(back_inserter(vec), 10, 0); //添加10个元素到vec
back_inserter接受一个指向容器的引用,返回一个与该容器绑定的插入迭代器。头文件iterator
int a1[] = {0,1,2,3,4,5,6,7,8,9};
int a2[sizeof(a1)/sizeof(*a1)]; //a2与a1大小一样
//ret指向拷贝到a2的尾元素之后的位置
auto ret = copy(begin(a1), end(a2), a2); //把a1的内容拷贝给a2
//将所有值为0的元素改为42
replace(ilist.begin(), ilist.end(), 0, 42);
//使用back_inserter按需要增长目标序列
replace_copy(ilist.cegin(), ilist.cend(), back_inserter(ivec), 0, 42);
//此调用后,ilist并未改变,ivec包含ilist的一份拷贝,不过原来在ilist中值为0的元素改为42
3、重排容器元素的算法
//练习10.9
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
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);
//unique重排输入范围,使得每个单词只出现一次
//排列在范围前部,返回指向不重复区域之后一个位置的迭代器
auto end_unique = unique(words.begin(), words.end());
output_words(words);
//使用向量操作erase删除重复单词
words.erase(end_unique, words.end());
output_words(words);
}
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if(!in){
cout << "打开输入文件失败!" << endl;
exit(1);
}
vector<string> words;
string word;
while(in >> word)
words.push_back(word);
elimDups(words);
return 0;
}
10.3 定制操作
1、向算法传递函数
stable_sort 稳定排序算法,可以维持相等元素的原有顺序。
//练习10.13
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
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 &s1) //找出大于5的string,返回true
{
return s1.size() >= 5;
}
int main(int argc, char *argv[])
{
ifstream in(argv[1]);
if(!in){
cout << "打开输入文件失败!" << endl;
exit(1);
}
vector<string> words;
string word;
while(in >> word)
words.push_back(word);
output_words(words.begin(), words.end());
//partition接受一个谓词,对容器内容进行划分,true排在容器的前半部分,false排在后半部分
auto iter = partition(words.begin(), words.end(), five_or_more);
output_words(words.begin(), words.end());
return 0;
}
2、lambda表达式
可调用对象,函数、函数指针、重载了函数调用运算符的类、lambda表达式。
一个lambda表达式表示一个可调用的代码单元,可理解为一个未命名的内联函数。
[capture list] (parameter list) -> return type {function body}
参数列表和返回类型可忽略,必须包含捕获列表(一个lambda所在函数中定义的局部变量的列表)和函数体。
//第三个参数为lambda表达式,实现isShorter的功能
stable_sort(words.begin(), words.end(), [](const string &a, const string &b)
{ return a.size() < b.size();});
上面空的捕获列表表明此lambda表达式不使用它所在函数中的任何局部变量。
//练习10.16
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
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)
{
sort(words.begin(), words.end()); //按字典序排序,以便查找重复单词
output_words(words);
//unique重排输入范围,使得每个单词只出现一次
//排列在范围前部,返回指向不重复区域之后一个位置的迭代器
auto end_unique = unique(words.begin(), words.end());
//使用向量操作erase删除重复单词
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); //将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 << "打开输入文件失败!" << endl;
exit(1);
}
vector<string> words;
string word;
while(in >> word)
words.push_back(word);
biggies(words, 4);
return 0;
}
3、lambda捕获和返回
值捕获:与参数不同,被捕获的变量的值是在lambda创建时拷贝,而不是调用时拷贝。
引用捕获:当以引用方式捕获一个变量时,必须保证在lambda执行时变量是存在的。
隐式捕获:&隐式引用捕获,=隐式值捕获,显式捕获可以和隐式捕获混合使用
可变lambda:值捕获的方式可以加mutable改变值,引用捕获取决于是否const
指定lambda返回类型:使用尾置返回类型
4、参数绑定
标准库bind函数: auto newCallable = bind(callable, arg_list) newCallable本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的callable的参数。 arg_list参数可能包含形如_n的名字,n为整数,这些参数是“占位符”。数值n表示生成的可调用对象中参数的位置。头文件 functional。
//练习10.22
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<algorithm>
#include<functional>
using namespace std;
using namespace std::placeholders;
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;
}
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)
{
output_words(words);
//计算满足size >= sz的元素的数目
//count_if:接受一对迭代器,和一个谓词,返回一个计数值,表示谓词有多少次为真。
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;
exit(1);
}
vector<string> words;
string word;
while(in >> word)
words.push_back(word);
biggies(words, 6);
return 0;
}
10.4、再探迭代器
1、插入迭代器
back_inserter front_inserter inserter
2、iostream迭代器
3、反向迭代器
流迭代器和forward_list不支持创建反向迭代器。
//10.37给定一个包含10个元素的vector,将位置3到7之间的元素按逆序拷贝到一个list中
#include<iostream>
#include<vector>
#include<algorithm>
#include<list>
#include<iterator>
using namespace std;
int main()
{
vector<int> vi = {0,1,2,3,4,5,6,7,8,9};
ostream_iterator<int> out_iter(cout, " ");
copy(vi.cbegin(), vi.cend(), out_iter);
cout << endl;
list<int> li;
vector<int>::reverse_iterator re(vi.begin() + 2);
vector<int>::reverse_iterator rb(vi.begin() + 7);
copy(rb, re, back_inserter(li));
copy(li.begin(), li.end(), out_iter);
cout << endl;
return 0;
}
10.5、泛型算法结构
1、5类迭代器
2、算法形参模式
10.6、特定容器算法