泛型算法的实现独立于容器,可以操作在各个容器以及各种内置类型上。
iterator迭代器对指针实现了泛化,泛型算法通过传入的first和last迭代器,脱离容器来进行想用的操作。
泛型算法包含在头文件<algorithm>中,现在我们看一下常见的几种泛型算法是怎么实现的。
1.泛型算法sort
泛型sort的定义如下:
inline void sort(const _RanIt _First, const _RanIt _Last, _Pr _Pred)
// order [_First, _Last), using _Pred
_First和_Last为迭代器,_Pred为函数对象(比较方式,也可以为lamda表达式),sort即将_First到_Last的内容按照_Pred的方式进行排序。
# include<algorithm>
# include<vector>
int main()
{
vector<int> arr{1,2,3,4,5,6,8};
sort(arr.begin(), arr.end(), greater<int>());
for (auto ele : arr)
{
cout << ele << ends;
}
return 0;
}
如上示例,会将vector里面的元素从大到小进行排列。
sort算法一般要求类型有<=或者>=等比较方式,内置类型都有这样的比较方式,对于非内置类型,我们可以通过函数对象或者lamda表达式自定义比较方式。
2.find和find_if
find的定义如下:
template<class _InIt, class _Ty> inline
_InIt find(_InIt _First, _InIt _Last, const _Ty% _Val);
会返回_First到_Last之间第一个于_Val相等的元素的迭代器。
find_if的定义如下:
template<class _InIt, class _Pr> inline
_InIt find_if(_InIt _First, _InIt _Last, _Pr _Pred);
找到满足指定条件的元素第一次出现的位置并返回。
下面是官方的一个示例:
// alg_find_if.cpp
// compile with: /EHsc
#include <list>
#include <algorithm>
#include <iostream>
bool greater10 ( int value )
{
return value >10;
}
int main( )
{
using namespace std;
list <int> L;
list <int>::iterator Iter;
list <int>::iterator result;
L.push_back( 5 );
L.push_back( 10 );
L.push_back( 15 );
L.push_back( 20 );
L.push_back( 10 );
cout << "L = ( " ;
for ( Iter = L.begin( ) ; Iter != L.end( ) ; Iter++ )
cout << *Iter << " ";
cout << ")" << endl;
result = find_if( L.begin( ), L.end( ), &greater10 );
if ( result == L.end( ) )
cout << "There is no element greater than 10 in list L."
<< endl;
else
{
result++;
cout << "There is an element greater than 10 in list L,"
<< "\n and it is followed by a "
<< *(result) << "." << endl;
}
}
上例中自定义了一个返回型为bool的函数greater10,将此函数的地址作为参数传递给sort,greater10会作为查找的一个条件。
3.绑定器std::bind
std::function和std::bind是C++11的新标准,程序媛可以更方便的使用标准。
std::bind会将函数的某个参数绑定上一个固定的值,形成一个新的函数(函数对象),可存于function中,如下例:
# include<functional>
# include<iostream>
using namespace std;
void Test(int a, int b)
{
cout << "a=" << a << endl << "b=" << b << endl;
}
int main()
{
//我们可以用std::function将绑定的结果进行保存
function<void(int)> f = bind(Test, 1, placeholders::_1);// placeholders::_1表示函数的第一个参数
//上面已经将Test的第一个参数与1进行绑定,形成的新函数为f,我们调用f的时候只要传入一个参数,作为第二个参数
f(2);//输出a=1,b=2
return 0;
}
上述的Test函数当然也可以为类中的某成员函数。当然bind也可以绑定多个函数,如:
参考博客:https://www.cnblogs.com/gtarcoder/p/4803205.html
using std::placeholders::_1;
//查找集合中大于5小于等于10的元素个数
auto f = std::bind(
std::logic_and<bool>(),
std::bind(std::greater<int>(), _1, 5),
std::bind(std::less_equal<int>(), _1, 10));
int count = std::count_if(coll.begin(), coll.end(), f);
同时std还提供了bind1st和bind2nd来针对二元函数的绑定操作。
如果大家想要了解bind的底层实现,可以参考博客:
https://blog.csdn.net/weixin_34153893/article/details/93150753
4.取反器
取反器是即是对函数对象执行取反,例如某个函数以前实现的功能是大于某个值,那么取反后的功能即为小于等于某个值。
关于取反器的功能可以参见下面的博客,比较简单,没必要重复整理了。
https://blog.csdn.net/TUJI67/article/details/89737292
5.函数对象
函数对象即是有()重载的类,经常应用在泛型算法中,可以写成内联函数
template<typename T>
class Sum
{
public:
int operator()(T a,T b)//()的重载
{
return a+b;
}
};
Sum sum;
int ret =sum(10,20);
如上是一个函数对象的示例,非常简单吧。另外,stl库函数一般都是二元函数,如果我们需要一元函数可以巧妙的利用邦定器和函数对象来实现一元函数。