算法的概述
算法部分主要由头文件,和组成。
是所有STL头文件中最大的一个,其中常用到的功能范围涉及到比较、交换、查找、遍历操作、复制、修改、反转、排序、合并等等。
体积很小,只包括几个在序列上面进行简单数学运算的模板函数,包括加法和乘法在序列上的一些操作。
中则定义了一些模板类,用以声明函数对象。
STL提供了大量实现算法的模版函数,只要我们熟悉了STL之后,许多代码可以被大大的化简,只需要通过调用一两个算法模板,就可以完成所需要的功能,从而大大地提升效率。
算法的分类:
操作对象
直接改变容器的内容
将原容器的内容复制一份,修改其副本,然后传回该副本
功能:
非可变序列算法 指不直接修改其所操作的容器内容的算法
计数算法 count、count_if
搜索算法 search、find、find_if、find_first_of、…
比较算法 equal、mismatch、lexicographical_compare
可变序列算法 指可以修改它们所操作的容器内容的算法
删除算法 remove、remove_if、remove_copy、…
修改算法 for_each、transform
排序算法 sort、stable_sort、partial_sort、
排序算法 包括对序列进行排序和合并的算法、搜索算法以及有序序列上的集合操作
数值算法 对容器内容进行数值计算
常用算法汇总
常用的查找算法:
adjacent_find()( adjacent 是邻近的意思),binary_search(),count(),
count_if(),equal_range(),find(),find_if()。
常用的排序算法:
merge(),sort(),random_shuffle()(shuffle是洗牌的意思) ,reverse()。
常用的拷贝和替换算法:
copy(), replace(),
replace_if(),swap()
常用的算术和生成算法:
accumulate()( accumulate 是求和的意思),fill(),。
常用的集合算法:
set_union(),set_intersection(),
set_difference()。
常用的遍历算法:
for_each(), transform()( transform 是变换的意思)
函数对谓词定义
函数对象:
重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象。一个类对象,表现出一个函数的特征,就是通过“对象名+(参数列表)”的方式使用一个类对象,如果没有上下文,完全可以把它看作一个函数对待。
这是通过重载类的operator()来实现的。
“在标准库中,函数对象被广泛地使用以获得弹性”,标准库中的很多算法都可以使用函数对象或者函数来作为自定的回调行为;
谓词:
一元函数对象:函数参数1个;
二元函数对象:函数参数2个;
一元谓词 函数参数1个,函数返回值是bool类型,可以作为一个判断式
谓词可以使一个仿函数,也可以是一个回调函数。
二元谓词 函数参数2个,函数返回值是bool类型
预定义函数对象和函数适配器
预定义函数对象基本概念:标准模板库STL提前定义了很多预定义函数对象,#include 必须包含。
//1使用预定义函数对象:
//类模板plus<> 的实现了: 不同类型的数据进行加法运算
void main41()
{
plus intAdd;
int x = 10;
int y = 20;
int z = intAdd(x, y); //等价于 x + y
cout << z << endl;
plus<string> stringAdd;
string myc = stringAdd("aaa", "bbb");
常用的函数适配器
标准库提供一组函数适配器,用来特殊化或者扩展一元和二元函数对象。常用适配器是:
1绑定器(binder): binder通过把二元函数对象的一个实参绑定到一个特殊的值上,将其转换成一元函数对象。C++标准库提供两种预定义的binder适配器:bind1st和bind2nd,前者把值绑定到二元函数对象的第一个实参上,后者绑定在第二个实参上。
2取反器(negator) : negator是一个将函数对象的值翻转的函数适配器。标准库提供两个预定义的ngeator适配器:not1翻转一元预定义函数对象的真值,而not2翻转二元谓词函数的真值。
常用函数适配器列表如下:
bind1st(op, value)
bind2nd(op, value)
not1(op)
not2(op)
遍历算法
for_each
for_each: 用指定函数依次对指定范围内所有元素进行迭代访问。该函数不得修改序列中的元素。
void show(const int &iItem)
{
cout << iItem;
}
main()
{
int iArray[] = {0,1,2,3,4};
vector vecInt(iArray,iArray+sizeof(iArray)/sizeof(iArray[0]));
for_each(vecInt.begin(), vecInt.end(), show);
//结果打印出0 1 2 3 4
}
transform
transform: 与for_each类似,遍历所有元素,但可对容器的元素进行修改
int increase (int i)
{
return i+1;
}
main()
{
vector vecIntA;
vecIntA.push_back(1);
vecIntA.push_back(3);
vecIntA.push_back(5);
vecIntA.push_back(7);
vecIntA.push_back(9);
transform(vecIntA.begin(),vecIntA.end(),vecIntA.begin(),increase); //vecIntA : {2,4,6,8,10}
}
adjacent_find
在iterator对标识元素范围内,查找一对相邻重复元素,找到则返回指向这对元素的第一个元素的迭代器。否则返回past-the-end。
vector vecInt;
vecInt.push_back(1);
vecInt.push_back(2);
vecInt.push_back(2);
vecInt.push_back(4);
vecInt.push_back(5);
vecInt.push_back(5);
vector<int>::iterator it = adjacent_find(vecInt.begin(), vecInt.end()); //*it == 2
count_if
假设vector vecIntA,vecIntA包含1,3,5,7,9元素
//先定义比较函数
bool GreaterThree(int iNum)
{
if(iNum>=3)
{
return true;
}
else
{
return false;
}
}
int iCount = count_if(vecIntA.begin(), vecIntA.end(), GreaterThree);
//此时iCount == 4
find_if
find_if: 使用输入的函数代替等于操作符执行find。返回被找到的元素的迭代器。
假设vector vecIntA,vecIntA包含1,3,5,3,9元素
vector::it = find_if(vecInt.begin(),vecInt.end(),GreaterThree);
此时 it==3, (it+1)==5, (it+2)==3, (it+3)==9
repalce
replace(beg,end,oldValue,newValue): 将指定范围内的所有等于oldValue的元素替换成newValue。
vector vecIntA;
vecIntA.push_back(1);
vecIntA.push_back(3);
vecIntA.push_back(5);
vecIntA.push_back(3);
vecIntA.push_back(9);
replace(vecIntA.begin(), vecIntA.end(), 3, 8); //{1,8,5,8,9}
replace_if
replace_if : 将指定范围内所有操作结果为true的元素用新值替换。
用法举例:
replace_if(vecIntA.begin(),vecIntA.end(),GreaterThree,newVal)
其中 vecIntA是用vector声明的容器
GreaterThree 函数的原型是 bool GreaterThree(int iNum)
//把大于等于3的元素替换成8
vector vecIntA;
vecIntA.push_back(1);
vecIntA.push_back(3);
vecIntA.push_back(5);
vecIntA.push_back(3);
vecIntA.push_back(9);
replace_if(vecIntA.begin(), vecIntA.end(), GreaterThree, 8); // GreaterThree的定义在上面。
accumulate
accumulate: 对指定范围内的元素求和,然后结果再加上一个由val指定的初始值。
#include<numeric>
vector<int> vecIntA;
vecIntA.push_back(1);
vecIntA.push_back(3);
vecIntA.push_back(5);
vecIntA.push_back(7);
vecIntA.push_back(9);
int iSum = accumulate(vecIntA.begin(), vecIntA.end(), 100); //iSum==125