for_each()算法的意义,不仅仅是遍历容器中的每一个数据元素,更重要的意义在于,它在遍历容器中的每一个数据元素的同时,可以将某个操作应用到它访问的每一个数据元素上,从而直接实现对容器中大量元素的处理。同时,这个操作是可替换的,这就增加了处理数据的灵活性。
Function for_each (InputIterator first, InputIterator last, Function f);
for_each()算法可以接受三个参数,前两个通常是保存有待处理数据容器的迭代器,分别表示需要处理的数据的起始位置和终止位置;第三个参数就代表了对这个范围内的数据的处理方法,在形式上,它可以是一个函数,也可以是一个函数对象,甚至可以是一个 Lambda 表达式。虽然它的形式可以多种多样,但它都只可以接受一个参数,其类型就是容器中所保存数据的类型。
// 利用函数定义我们对数据的处理方法,对于低于 2000 元的工资,就增加 30%
// 函数只有一个参数,其类型是它将要处理的 vector 容器所保存数据的类型
// 因为要对容器中的数据进行修改,所以我们这里采用引用的参数形式
void AddSalary( int& nSalary )
{
// 判断数据是否满足条件
if( nSalary < 2000 )
nSalary *= 1.3; // 对数据进行处理
}
// 构造容器,保存数据
vector<int> vecSalary = {3500,1500,1000,2000,1200};
// 使用 for_each()算法,调用 AddSalary()函数对容器中的数据进行处理
for_each( vecSalary.begin(), vecSalary.end(), AddSalary );
这里需要注意的是, AddSalay()函数的参数是引用形式,所以在 AddSalary()函数中对参数的修改,实际上修改的是容器中的数据,这些修改都会反映到容器当中。如果这里的参数是值的形式,那么 AddSalary()函数的参数只是容器中数据的一个副本,在函数中对参数的修改不会反映到容器中。
find()算法可以从一个容器的某个范围中查找具有某个特定数值的数据元素
InputIterator find ( InputIterator first, InputIterator last, const T& value );
find()算法的前两个参数都是某个容器的迭代器,用于指定查找的起始位置和终止位置;第三个参数就是要查找的内容,它的数据类型跟容器中数据的类型相同。这里需要注意的是, find()算法会利用==
操作符将这里的目标内容跟容器中的数据元素进行相等比较,以确定某个元素是否符合条件,所以,这里的数据类型必须支持==
操作符进行相等比较。
在执行过程中, find()算法会将目标内容与容器中查找范围内的数据元素逐个进行相等比较,如果 find()算法找到了与之相同的数据元素,那么它将返回指向这个数据元素的迭代器;如果没有找到,那么返回的迭代器将指向这个容器的末尾位置。据此,我们可以判断查找是否成功。
// 创建保存商品信息的 vector 容器
vector<string> vecGoods;
// 老板进货,向容器中添加商品
vecGoods.push_back("Eraser");
vecGoods.push_back("Book");
vecGoods.push_back("Pen");
// …
// “老板,你这有没有卖铅笔?”,定义要购买的商品
string strGood = "Pencil";
// “稍等,让我找找看!”,在 vecGoods 中找“Pencil”
auto it = find( vecGoods.begin(), vecGoods.end(), strGood );
// 如果 find()函数返回的迭代器没有指向容器的末尾,
// 那就是找到想要的东西了
if( it != vecGoods.end() )
{
cout<<"恭喜,本店提供"<<strGood<<endl;
}
else // 如果迭代器指向容器末尾位置,则是没找到
{
cout<<"抱歉,本店不提供"<<strGood<<endl;
}
当需要根据某个特定条件来查找数据时, find()算法就无能为力了。不过好在 STL 中还有它的孪生兄弟——find_if()算法。 find_if()算法的原型如下:
InputIterator find_if ( InputIterator first, InputIterator last, Predicate pred );
find_if()算法的第三个参数是一个规则函数(包括函数对象或 Lambda 表达式),其返回值为 bool类型,并拥有一个跟容器中数据相同类型的参数。 find_if()算法就是用这个规则函数来表达某个特定的查找规则。
在执行 find_if()算法的时候,它会将查找范围内的数据逐个传递给这个规则函数,这个规则函数将根据一定的条件对其进行判断,如果符合条件,规则函数会返回 true,表示这个数据就是我们要找的数据, find_if()算法会返回指向这个数据的迭代器,表示找到一个符合条件的数据。反之,如果这个数不符合规则函数中的条件,规则函数会返回 false,表示当前数据不符合查找条件, find_if()算法就会将下一个数据传递给规则函数,开始同样地判断过程。这个过程会不断重复下去,直到找到符合条件的数据而返回指向这个数据的迭代器,或者是查找完整个查找范围,但未找到符合条件的数据而返回指向查找范围末尾的迭代器。
// 使用函数表达查找规则:查找及格分数
// 如果分数大于等于 60,就返回 true,表示及格,否则返回 false
bool ispass( int n )
{
if( n >= 60 )// 符合查找条件
{
return true;
}
else // 不符合查找条件
{
return false;
}
}
// 定义保存成绩的容器
vector<int> vecScores = {72,56,83,81,59,60};
// 定义查找的起始位置
auto it = vecScores.begin();
// 利用循环,逐个查找容器中符合条件的数据
do
{
// 在容器中查找符合条件的数据元素,
// 其中 ispass 表达了查找规则
it = find_if(it, vecScores.end(), ispass );
if ( vecScores.end() != it ) // 判断是否找到符合条件的数据
{
// 输出查找到的符合条件的数据
cout<<"找到及格分数: "<<(*it)<<endl;
// 将迭代器指向下一个位置,从新的位置开始下一次查找
++it;
}
else
{
// 如果没有找到,就退出循环
break;
}
} while( true );
除了 find()算法和 find_if()算法之外, STL 中的查找算法还有多个变种。
find_end()
算法能够从容器的末尾位置开始向前查找符合条件的数据;find_first_of()
算法会查找容器中某个元素首次出现的位置;adjacent_find()
算法会查找容器中重复出现的数据。另外,跟查找算法在容器中查找单个符合条件的数据不同, STL 还提供了搜索算法,也就是search()
算法和search_n()
算法,它们可以用于在容器中搜索与目标串相匹配的子串数据。
利用这些算法,我们可以直接对容器中那些符合某个条件的数据进行日常处理,而不必先用 find()算法找到这些数据再对其进行处理。
#include // 为了使用 vector 容器
#include // 为了使用 remove()和 replace_if()算法
#include
using namespace std;
// 判断分数是否不及格(小于 60)的函数
bool isfail(int nScore)
{
return nScore < 60 ? true : false;
}
int main()
{
// 待处理的成绩数据
vector<int> vecScores = {54,-1,-1,73,5,67};
// 从容器中删除缺考成绩-1
// remove()算法实质上是将待删除的数据移动到容器末尾部分来实现删除
// 所以我们这里要用 itend 保存 remove()算法返回的 vecScores 容器新的末尾位置
// 这样,从 vecScores.begin()到 itend 界定了容器中的有效数据的范围
// 而在 itend 之后 vecScores.end()之前的是被删除的无效数据
auto itend = remove(vecScores.begin(), vecScores.end(), -1); // 需要删除的元素
replace_if(vecScores.begin(),// 开始位置
itend, // vecScores 新的结束位置,不再是 end()得到的位置
isfail, // 判断数据是否符合替换条件
60); // 替换后的数据
// 输出处理后的数据
for(auto it = vecScores.begin();it != itend; ++it)
{
cout<<*it<<endl;
}
return 0;
}
使用 find_if ()算法,我们可以从容器中找到符合某个条件的数据,然而有的时候,我们只是想要知道容器中是否存在这样的数据,而并不想去访问这些数据本身。
// 用 any_of 算法判断处理后的成绩是否还有不及格的分数
bool bFail = any_of(vecScores.begin(),itend, isfail); // 用 isfail()函数判断分数是否及格
if(bFail)
{
cout<<"还有不及格的"<<endl;
}
else
{
cout<<"连一个不及格的都没有"<<endl;
}