泛型算法的关键概念:泛型算法本身不会执行容器的操作,它们只会运行于迭代器之上,执行迭代器的操作。泛型算法运行于迭代器之上而不会执行容器操作的特性带来了一个令人惊讶但非常必要的编程假定:算法永远不会改变底层容器的大小。算法可能改变容器中保存的元素的值,也可能在容器移动元素,但永远不会直接添加或删除元素。
1.初始泛型算法
1.1 只读算法
A.accumulate函数
头文件:numberic ; 目的:求和;它的三个参数:前两个求和元素的范围,第三个是参数和的初始值;
例子:
vector
vec;
int sum=accumulate(vec.begin(),vec.end(),0);// 求vec容器中元素和;初始值为0;
string sum1=accumulate(v.begin(),v.end(),string()); //把vector容器中的string元素都连接起来;
注意:第三个参量的类型决定了函数使用哪个加法运算符以及返回值的类型。
B. equal函数
目的:用于确定两个序列是否保存相同的值。它将第一个序列中的每个元素与第二个序列中的元素进行比较。它的三个参数:前两个表示第一个序列的元素范围,第三个表示第二个序列的首元素。
例子:
equal(roster1.cbegin(),roster1.cend(),roster2.cbegin()); //roster1可以是vector
,而roster2是list
。
1.2 写容器的元素算法
A. fill_n函数
目的:指定的迭代器元素范围内,进行赋值;它的三个参数:一个单迭代器、一个计数值和一个值。
例子:
vector
vec; //空vector;
fill_n(vec.begin(),v.end(),0); //将所有元素重置为0;
fill_n(vec.begin(),10,0); //由于vector容器中没有元素,这条语句的结果是未定义的。
B.back_inserter函数
头文件:iterator ;目的:接受一个指向容器的引用,返回一个与该容器绑定的插入迭代器。当我们通过这个迭代器赋值时,会调用push_back将一个给定的值插入容器中。
C.拷贝算法
目的:是另一个向目的位置迭代器指向的输出序列中元素写入数据的算法。它的三个迭代器:前两个表示一个输入范围,第三个表示目的序列的起始位置。
D.replace函数
目的:将容器中的给定元素用新元素替换;它的四个参数:前两个是迭代器,第三个表示搜素的值(被替换),第四个是新值(替换的值);
例子:
replace(ilist.begin(),ilst.end(),0,42); //将序列中所有值为了0的元素都改为42;
1.3 重排容器元素的算法
A.sort函数
目的:按字典顺序排序;它的参数:至少需要前后两个迭代器的范围;
B.unique函数
目的:排列在范围的前部,返回指向不重复区域之后一个位置的迭代器。将相邻的重复项都删除,并返回一个指向不重复值的范围末尾的迭代器。
例子:
#include
#include
#include
using namespace std;
void elimDups(vector
&word)
{
sort(word.begin(),word.end()); //按字典顺序排序word,以便查找重复单词;
for(auto k:word) //打印字母排序的word;
cout<
cout<
auto end_unique=unique(word.begin(),word.end()); //把word中相同的词单个单词顺序的后面;
word.erase(end_unique,word.end()); //删除重复的单词;
}
int main()
{
vector
vec;
fill_n(back_inserter(vec),10,0); //插入迭代器back_inserter,回调用push_back;
fill_n(vec.begin(),vec.size(),1); //fill_n(dest,n,val):接受一个迭代器、计数值、一个值;容器赋值语句;
for(auto c: vec)
cout<
cout<
int a1[]={0,1,2,3,4,5,6,7,8,9};
int a2[sizeof(a1)/sizeof(*a1)]; //保存a1与a2数组大小相同;
auto ret=copy(begin(a1),end(a1),a2) ;//把a1的内容拷贝给a2;
for(auto b:a2)
cout<
vector
vec1={the,quick,red,fox,jump,over,the,slow,red,turtle};
elimDups(vec1);
for(auto k:vec1)
cout<
cout<
return 0;
}
显示结果:

?
2.定制操作
A.谓词
谓词是一个可调用的表达式,其返回结果是一个能用作条件的值。谓词分为:一元谓词和二元谓词。几元谓词接受几元参数;
B.lambda函数
可调用对象定义;对于一个对象或一个表达式,如果可以对其使用调用运算符,则称为可调用的;可调用的对象有:函数、函数指针、重载函数调用运算符的类和lambda表达式。
lambda表达式形式:
[capture list](parameter list)->return type{function body};
capture list是一个lambda所在函数中定义的局部变量的列表(通常为空);
return type、parameter list和function body分别表示返回类型、参数列表和函数体。
调用find_if:查找第一个长度大于等于sz的元素;
auto wc=find_if(words.begin(),words.end(),[sz](const string &a){return a.size()>=sz;});
C.for_each算法
该算法接受一个可调用对象,并对输入序列中每个元素调用此对象:
for_each(wc,words.end(),[](const string &s){cout<
cout<
注意:为了指示编译器推断捕获列表,应在捕获列表中写一个&或=;&告诉编译器采用引用方式,=则表示采用值捕获方式。
3.参数绑定
标准库bind函数
头文件:functional ;它接受一个可调用对象,生成一个新的可调用对象来适应原对象的参数列表。
调用bind的形式:
auto newCallable=bind(callable, arg_list);
newCallable本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的callable的参数。arg_list中的参数可能包含形如_n的名字,_1是newCallable的第一个参数,_2为第二个参数,依次类推。
4.再探迭代器
迭代器有:插入迭代器、流迭代器、反向迭代器、移动迭代器;
4.1插入迭代器
插入器:是一种迭代器适配器,它接受一个容器,生成一个迭代器,能实现向给定容器添加元素。
插入迭代器三种类型:back_inserter(调用pus