非修改性序列算法是不用使用循环就可以从序列中中找出某些东西的工具。
可分为:
- for_each算法
- 元素计数算法
- 最小值和最大值算法
- 搜寻算法
- 区间比较算法
for_each()算法
函数原型:
for_each(Iterator begin ,Iterator end ,proc op)
算法主要对[begin,end]区间的每个元素调用op。
其中,op可以是一个函数指针,这个比较好理解。也可以是仿函数。
class Printer
{
public:
void operator () (int ele)
{
std::cout << ele << ", ";
}
};
其实就是重载了()操作符,使得调用形式跟函数一样,不过函数指针变成了函数对象。
使用仿函数,可以这样使用for_each()。
Printer pt;
cout << "l1" << endl;
for_each(l1.begin() ,l1.end() ,pt);
cout << endl;
其实,for_each()是有返回值的,这个例子比较有意思:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class SUM
{
private:
long sum_D;
public:
SUM():sum_D(0){}
void operator()(int elem)
{
sum_D += elem ;
}
operator double()
{
return static_cast<double>(sum_D);
}
};
int main()
{
vector<int> myvec;
int int_ary[] = {1 ,2 ,3 ,4 ,5};
myvec.assign(int_ary ,int_ary + 5);
double sum = for_each(myvec.begin() ,myvec.end() ,SUM());
cout << "The sum: " << sum << endl;
return 0;
}
输出值是15,从这个例子可以看出,for_each的返回值就是传入的第三个参数,即op;
所以,如果传入的是一个函数指针,那么将返回一个函数指针。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
void Print(int ele)
{
cout << ele << " ,";
}
int main()
{
typedef void (*FUNC)(int);
vector<int> myvec;
int int_ary[] = {1 ,2 ,3 ,4 ,5};
myvec.assign(int_ary ,int_ary + 5);
FUNC func = for_each(myvec.begin() ,myvec.end() ,Print);
func(2);
return 0;
}
以下是输出:
可以看出,通过调用func(2)输出了一个2;从而说明了返回的是函数的第三个参数。
元素计数
其实就是返回一个集合中满足条件的元素有多少个。
函数原型:
count(Iterator begin ,Iterator end ,const T & value);
count_if(Iterator begin ,Iterator end ,UnaryPredicate op);
有点麻烦的是第二个,UnaryPredicate又称为一元判定词。刚接触STL,并没有深入挖掘的准备,但对与一元判定词,看看count_if的实现就知道了。
template<typename _InputIterator, typename _Predicate>
typename iterator_traits<_InputIterator>::difference_type
count_if(_InputIterator __first, _InputIterator __last, _Predicate __pred)
{
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
__glibcxx_function_requires(_UnaryPredicateConcept<_Predicate,
typename iterator_traits<_InputIterator>::value_type>)
__glibcxx_requires_valid_range(__first, __last);
typename iterator_traits<_InputIterator>::difference_type __n = 0;
for (; __first != __last; ++__first)
if (__pred(*__first))
++__n;
return __n;
}
前面的就不管了,不知道是什么,但根据if (__pred(*__first))可以看出来,一元判定词有一下特点:
- 可像函数一样调用
- 只有一个参数
- 返回值是bool类型
所以,这里直接传递一个函数指针,肯定也是符合要求的。
在STL中,这里经常使用的是bind2nd();比如,统计大于2的元素个数:
int ctg = count_if(myvector.begin() ,myvector.end() ,bind2nd(greater<int>)(),2);
其实bind2nd(greater<int>,2)的作用就是生成一个一元判定词对象。它返回了一个binder2nd对象。
/// One of the @link binders binder functors@endlink.
template<typename _Operation>
class binder2nd
: public unary_function<typename _Operation::first_argument_type,
typename _Operation::result_type>
{
protected:
_Operation op;
typename _Operation::second_argument_type value;
public:
binder2nd(const _Operation& __x,
const typename _Operation::second_argument_type& __y)
: op(__x), value(__y) { }
typename _Operation::result_type
operator()(const typename _Operation::first_argument_type& __x) const
{ return op(__x, value); }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 109. Missing binders for non-const sequence elements
typename _Operation::result_type
operator()(typename _Operation::first_argument_type& __x) const
{ return op(__x, value); }
}
可以看出,binder2nd是一个名副其实的仿函数,只有一个参数,返回值为bool 类型。
我刚才还疑惑这里为什么不直接用一个二元判定词呢,不过现在想清楚了。
因为这样的话,一个count_if()函数模板既可以满足仿函数,又可以满足函数指针,还可以满足这种看起来需要二元判定词的。