10.1 概述
大多数算法都定义在头文件algorithm中。标准库还在头文件numeric中定义了一组数值泛型算法 算法并不是直接操作容器,而是遍历有两个迭代器指定的一个元素范围,迭代器令算法不依赖于容器,find用元素类型的==运算符完成每个元素与给定值的比较。其他算法可能要求元素类型支持<运算符 算法永远不会改变底层容器的大小,算法可能改变容器中保存元素的值,也可能在容器内移动元素,但是永远不会直接添加或删除元素。标准库定义了一类特殊的迭代器(插入器),当给这类迭代器赋值时,会在底层的容器上执行插入操作,算法可以操作这样一个迭代器实现容器中添加元素的效果,但是算法本身永远不会做这样的操作。
auto result = find ( vec. cbegin ( ) , vec. cend ( ) , val) ;
10.2 初识泛型算法
大多数算法遍历输入范围的方式都相似,但他们使用范围中元素的方式不同。理解算法的最基本方法就是了解他们是否读取元素、改变元素或者是重排元素。
10.2.1 只读算法
accumulate定义在头文件numeric中。第三个参数的和的初值。其第三个参数的类型决定了函数中使用那个加法运算符以及返回值的类型。序列中的元素类型必须与第三个参数匹配或者能转换为第三个参数的类型。
int sum = accumulate ( vec. cbegin ( ) , vec. cend ( ) , 0 ) ;
string sum = accumulate ( vec. cbegin ( ) , vec. cend ( ) , string ( "" ) ) ;
string sum = accumulate ( vec. cbegin ( ) , vec. cend ( ) , "" ) ;
equal算法,用于确定两个序列是否保存相同的值。前两个迭代器表示第一个序列的范围,第三个迭代器表示第二个序列的首元素。元素类型不必一样,只要能用==来比较两个元素类型即可。基于一个重要的假设,即第二个序列至少与第一个序列一样长。
equal ( roster1. cbegin ( ) , roster1. cend ( ) , roster2. cbegin ( ) ) ;
10.2.2 写容器元素的算法
fill算法,将给定值赋予输入序列的每一个元素
fill ( vec. begin ( ) , vec. end ( ) , 10 ) ;
fill_n函数
fill_n ( dext, n, val) ;
插入迭代器:当通过一个插入迭代器赋值时,一个与赋值号右侧值相等的元素被添加到容器中。 back_inserter,是一个定义在头文件iterator中的一个函数,其接受一个指向容器的引用,返回一个与该容器绑定的插入迭代器,当通过此迭代器赋值时,赋值运算符 会调用push_back将一个具有给定值的元素添加到容器中。
vector< int > vec;
auto it = back_inserter ( vec) ;
* it = 42 ;
fill_n ( back_insetrer ( vec) , 10 , 0 ) ;
拷贝算法:必须保证第二个序列的元素个数至少等于第一个序列
int a1[ ] = { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 } ;
int a2[ sizeof ( a1) / sizeof ( * a1) ] ;
auto ret = copy ( begin ( a1) , end ( a2) , a2) ;
replace算法,将所有给定值的元素都改为另一个值。此算法接受一个额外的迭代器,调用后,原序列保持不变,ivec包含list的一份拷贝,不过原来list中0的元素改为42
replace ( list. begin ( ) , list. end ( ) , 0 , 42 ) ;
replace ( list. begin ( ) , list. end ( ) , back_inserter ( ivec) , 0 , 42 ) ;
10.2.3 重排容器元素的算法
消除重复元素
void elimDups ( vector< string> & words) {
sort ( words. begin ( ) . words. end ( ) ) ;
auto end_unique = unique ( words. begin ( ) , words. end ( ) ) ;
words. erase ( end_unique, word. end ( ) ) ;
}
标准库算法对迭代器而不是容器进行操作,因此,算法不能直接添加或删除元素
10.3 定制操作
10.3.1 向算法传递函数
sort函数接受第三个参数,此参数是一个谓词。谓词是一个可调用的表达式,其返回结果是一个能用作条件的值。谓词可以分为一元谓词(只接受一个参数)和二元谓词(有两个参数),元素类型必须能转换为谓词的参数类型。
bool isShorter ( const string & s1, const string & s2) {
return s1. size ( ) < s2. size ( ) ;
}
sort ( words. begin ( ) , words. end ( ) , isShorter) ;
stable_sort函数:长度相同按字典序进行排序
10.3.2 lambda表达式
一个lambda表达式表示一个可调用的代码单元。可以在函数体内部。 lambda只有在其捕获一个它所在函数中的局部变量,才能在函数体内使用该变量
void biggies ( vector< string> & words, vector< string> :: size_type sz) {
elimDups ( words) ;
stable_sort ( words. begin ( ) , words. end ( ) , isShorter) ;
auto wc = find_if ( words. begin ( ) , words. end ( ) ,
[ sz] ( const string & a) { return a. size >= sz; } ) ;
for_each ( wc, words. end ( ) , [ ] ( const string & s) { cout << s << " " } ) ;
cout << endl;
}
捕获列表只用于局部非static变量,lamdba可以直接使用局部static变量和在它所在函数之外声明的名字。
10.3.3 lambda捕获和返回
10.3.4 参数绑定
10.4 再探迭代器
10.4.1 插入迭代器
10.4.2 iostream迭代器
10.4.3 反向迭代器
10.5 泛型算法结构
10.5.1 5类迭代器
10.5.2 算法形参模式
10.5.3 算法命名规范
10.6 特定容器算法