函数对象、函数适配器和算法

1、函数对象     

定义了调用操作符的类型,为类类型的对象提供重载函数的调用操作符,其对象称之为函数对象。

(1)函数对象使用方式

调整数组顺序使奇数位于偶数前面(数组)。输入一个整数数组,调整数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。要求时间复杂度为O(n)。使用函数对象处理方式.

代码如下:

#include <iostream>  
using namespace std;  
  
//函数对象  
template<class T>  
struct IsOdd  
{  
    bool operator() (T x){return (x & 1)?true: false;}  
};  
//函数功能 : 调整数组顺序使奇数位于偶数前面    
//函数参数 : pArray指向数组的指针,nLen为数组长度    
//返回值 :   无    
template <class T, class F>  
void PartionArray(T *pArray, int nLen, F func)  
{    
    int i = -1;    
    for(int j = 0; j < nLen; j++)    
    {    
        if(func(pArray[j])) //满足调整条件    
        {    
            i++;    
            T tmp = pArray[j];    
            pArray[j] = pArray[i];    
            pArray[i] = tmp;    
        }    
    }    
}    
//测试用例  
int main()  
{  
    short a[] = {1,2,3,4,5,6};  
    long b[] = {1,2,3,4,5,6};  
    PartionArray(a, 6, IsOdd<short>());   
    PartionArray(b, 6, IsOdd<long>());   
    return 0;  
}  

(2)函数指针处理

与函数对象的处理方式不同,函数指针处理方式如下。

代码如下:

bool IsOdd(int x)    
{    
    return (x & 1)? true: false;    
}    
//函数功能 : 调整数组顺序使奇数位于偶数前面    
//函数参数 : pArray指向数组的指针,nLen为数组长度    
//返回值 :   无    
void PartionArray(int *pArray, int nLen, bool (*func)(int))    
{    
    int i = -1;    
    for(int j = 0; j < nLen; j++)    
    {    
        if(func(pArray[j])) //满足调整条件    
        {    
            i++;    
            int tmp = pArray[j];    
            pArray[j] = pArray[i];    
            pArray[i] = tmp;    
        }    
    }    
}  

(3)stl的函数对象

相比函数指针,函数对象能很好的满足STL的抽象要求。STL中的函数对象是与STL的算法联系在一起。

(3-1)stl函数对象定义

1)函数对象基类

STL定义了两个类,作为一元操作和二元操作的基类,这两个基类仅仅是使用了内嵌型别技术。

//用来定义一元操作的参数类别和返回值类别  
template <class Arg, class Result>  
struct unary_function {  
    typedef Arg argument_type;  //内嵌型别技术  
    typedef Result result_type;  
};  
//用来定义二元操作的参数类别和返回值类别  
template <class Arg1, class Arg2, class Result>  
struct binary_function {  
     typedef Arg1 first_argument_type;  
     typedef Arg2 second_argument_type;  
     typedef Result result_type;  
};  
2)函数对象使用类型

包含一元和二元操作的函数对象。

代码如下:

//一元操作,就两个  
template <class T>  
struct negate : public unary_function<T, T> {  
    T operator()(const T& x) const { return -x; }  
};  
template <class T>  
struct logical_not : public unary_function<T,bool> {  
    bool operator()(const T& x) const { return !x; }  
};  
//加减乘除取模  
template <class T>  
struct plus : public binary_function<T, T, T> {  
    T operator()(const T& x, const T& y) const { return x + y; }  
};  
template <class T>  
struct minus : public binary_function<T, T, T> {  
    T operator()(const T& x, const T& y) const { return x - y; }  
};  
template <class T>  
struct multiplies : public binary_function<T, T , T> {  
    T operator()(const T& x, const T& y) const { return x * y; }  
};  
template <class T>  
struct divides : public binary_function<T ,T, T> {  
    T operator()(const T& x, const T& y) const { return x / y; }  
};  
template <class T>  
struct modulus : public binary_function<T, T, T> {  
    T operator()(const T& x, const T& y) const { return x % y; }  
};  
//关系运算  
template <class T>  
struct equal_to : public binary_function<T, T, bool> {  
    bool operator()(const T& x, const T& y) const { return x == y; }  
};  
template <class T>  
struct not_equal_to : public binary_function<T, T,bool> {  
    bool operator()(const T& x, const T& y) const { return x != y; }  
};  
template <class T>  
struct greater : public binary_function<T, T, bool> {  
    bool operator()(const T& x, const T& y) const { return x > y; }  
};  
template <class T>  
struct less : public binary_function<T, T, bool> {  
    bool operator()(const T& x, const T& y) const { return x < y; }  
};  
template <class T>  
struct greater_equal : public binary_function<T, T, bool> {  
    bool operator()(const T& x, const T& y) const { return x >= y; }  
};  
template <class T>  
struct less_equal : public binary_function<T, T, bool> {  
    bool operator()(const T& x, const T& y) const { return x <= y; }  
};  
//逻辑运算  
template <class T>  
struct logical_and : public binary_function<T, T, bool>{  
    bool operator()(const T& x, const T& y) const { return x && y; }  
};  
template <class T>  
struct logical_or : public binary_function<T, T, bool>  
{  
    bool operator()(const T& x, const T& y) const { return x || y; }  
};  


(3-1)stl函数对象使用

数组排序,代码如下:

#include <iostream>  
#include <algorithm>  
using namespace std;  
int main()  
{  
    int a[] = {1,3,2,4,5,7};  
    sort(&a[0], &a[6]);  
    for(int i = 0; i < 6; i++)  
        cout<<a[i]<<' ';  
     cout<<endl;  
    return 0;  
}  

 这个排序算法默认是递增排序,如果是递减排序,就在函数实参中加入一个函数对象即可。

#include <iostream>  
#include <functional>  
#include <algorithm>  
using namespace std;  
int main()  
{  
    int a[] = {1,3,2,4,5,7};  
    sort(&a[0], &a[6], greater<int>());  
    for(int i = 0; i < 6; i++)  
         cout<<a[i]<<' ';  
     cout<<endl;  
     return 0;  
}  

2、 函数适配器

 函数适配器是复杂点的函数对象,用于特化和扩展一元和二元函数对象。

(1) 函数适配器使用

 函数适配器类型包括:

1)绑定器,通过将一个操作数绑定到给定值而将二元函数对象转换为一元函数。

2)求反器,它将谓词函数对象的真值求反。

#include <iostream>  
#include <functional>  
#include <vector>  
#include <algorithm>  
using namespace std;  
int main()  
{  
    vector<int> vec(10, 1);  
    int count1 = count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 10));       //求容器中小于等于10的元素个数  
    int count2 = count_if(vec.begin(), vec.end(), not1(bind2nd(less_equal<int>(), 10))); //求容器中不小于等于10的元素个数,正好是上面结果的取反  
    cout<<count1<<' '<<count2<<endl;  //10 0  
    return 0;  
}  

(2)绑定器和求反器

(2-1)绑定器

 如 binder1st 绑定器类型,它的模板中只有一个形参,它继承自unary_function模板类型,有两个形参。第一个模板实参是个函数对象,继承自unary_function或binary_function;第二个模板实参是操作的对象,也就是值。

代码如下:(根据STL源码整理的)

//绑定第一个参数  
template <class Operation>   
class binder1st: public unary_function<typename Operation::second_argument_type, typename Operation::result_type> {  
public:  
   binder1st(const Operation& x, const typename Operation::first_argument_type& y) : op(x), value(y) {} //构造函数  
   typename Operation::result_type operator()(const typename Operation::second_argument_type& x) const {  
       return op(value, x);  //固定第一个参数  
   }  
protected:  
   Operation op;  
   typename Operation::first_argument_type value;  
};  
//绑定第二个参数  
template <class Operation>   
class binder2nd: public unary_function<typename Operation::first_argument_type,typename Operation::result_type> {  
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);  //固定第二个参数  
    }  
protected:  
    Operation op;  
    typename Operation::second_argument_type value;  
};  
//绑定器对外封装的接口  
template <class Operation, class T>  
inline binder1st<Operation> bind1st(const Operation& fn, const T& x) {  
    typedef typename Operation::first_argument_type Arg1_type;  
    return binder1st<Operation>(fn,Arg1_type(x));  
}  
template <class Operation, class T>  
inline binder2nd<Operation> bind2nd(const Operation& fn, const T& x) {  
    typedef typename Operation::second_argument_type Arg2_type;  
    return binder2nd<Operation>(fn, Arg2_type(x));  
}  


(2-2)求反器

代码如下

//一元操作求反  
template <class Predicate>  
class unary_negate: public unary_function<typename Predicate::argument_type, bool> {  
protected:  
    Predicate pred;  
public:  
    explicit unary_negate(const Predicate& x) : pred(x) {}  
    bool operator()(const typename Predicate::argument_type& x) const {  
    return !pred(x);  
   }  
};  
//二元操作求反  
template <class Predicate>   
class binary_negate : public binary_function<typename Predicate::first_argument_type, typename Predicate::second_argument_type,bool> {  
protected:  
    Predicate pred;  
public:  
    explicit binary_negate(const Predicate& x) : pred(x) {}  
    bool operator()(const typename Predicate::first_argument_type& x, const typename Predicate::second_argument_type& y) const {  
        return !pred(x, y);   
    }  
};  
//外部接口  
template <class Predicate>  
inline unary_negate<Predicate> not1(const Predicate& pred)  
{  
    return unary_negate<Predicate>(pred);  
}  

template <class Predicate>  
inline binary_negate<Predicate> not2(const Predicate& pred)  
{  
    return binary_negate<Predicate>(pred);  
} 


3、函数对象与算法

使用函数对象、函数适配器作为算法的参数,在函数对象中提供操作函数处理判断逻辑,实现算法代码重用。
步骤演示如下

算法count_if(vec.begin(), vec.end(),bind2nd(less_equal<int>(), 10),count1)具体执行:

1)执行bind2nd(less_equal<int>(),10)这个函数,这个函数会返回一个binder2nd的函数对象.

注意构造这个函数对象的时候,binder2nd(constOperation& x, const typename Operation::second_argument_type& y) :op(x), value(y) {} 。

第二个参数value的值设置为10,而第一个参数op设置成less_equal<int>()这个函数对象。

2)在count_if中,pred(*first)其实就是binder2nd中的运算,而这个运算的第二个参数是固定的,也就是10,所以pred只传递了一个实参进去就可以了。

3)符合pred 函数对象条件的,记录到参数n中


完整的测试代码如下:(根据stl修改的)

#include <iostream>  
#include <vector>  
using namespace std;  
   
//count_if函数  
template <class InputIter, class Predicate, class Size>  
void count_if(InputIter first, InputIter last, Predicate pred, Size& n) {  
   for ( ; first != last; ++first)  
       if (pred(*first))  
            ++n;  
}  
template <class InputIter, class Predicate>  
typename iterator_traits<InputIter>::difference_type count_if(InputIter first, InputIter last, Predicate pred) {  
   typename iterator_traits<InputIter>::difference_type n = 0;  
    for ( ; first != last; ++first)  
        if (pred(*first))  
            ++n;  
    return n;  
} 

//用来定义一元操作的参数类别和返回值类别  
template <class Arg, class Result>  
struct unary_function {  
    typedef Arg argument_type;  
    typedef Result result_type;  
};  
//用来定义二元操作的参数类别和返回值类别  
template <class Arg1, class Arg2, class Result>  
struct binary_function {  
    typedef Arg1 first_argument_type;  
    typedef Arg2 second_argument_type;  
    typedef Result result_type;  
};  
//本测试之用到关系函数对象  
template <class T>  
struct less_equal : public binary_function<T, T, bool> {  
    bool operator()(const T& x, const T& y) const { return x <= y; }  
};  
//绑定第二个参数  
template <class Operation>   
class binder2nd: public unary_function<typename Operation::first_argument_type,typename Operation::result_type> {  
public:  
    binder2nd(const Operation& x, const typename Operation::second_argument_type& y) : op(x), value(y) { cout<<"binder2nd Constructor"<<endl; }  
    typename Operation::result_type operator()(const typename Operation::first_argument_type& x) const {  
        cout<<"binder2nd's operator()"<<endl;  
        return op(x, value);  //固定第二个参数  
    }  
protected:  
    Operation op;  
    typename Operation::second_argument_type value;  
};  
//外部接口  
template <class Operation, class T>  
inline binder2nd<Operation> bind2nd(const Operation& fn, const T& x) {  
    typedef typename Operation::second_argument_type Arg2_type;  
    return binder2nd<Operation>(fn, Arg2_type(x));  
}  
//一元操作求反  
template <class Predicate>  
class unary_negate: public unary_function<typename Predicate::argument_type, bool> {  
protected:  
    Predicate pred;  
public:  
    explicit unary_negate(const Predicate& x) : pred(x) { cout<<"unary_negate Constructor"<<endl; }  
    bool operator()(const typename Predicate::argument_type& x) const {  
    cout<<"unary_negate's operator()"<<endl;  
    return !pred(x);  
}  
};  
//外部接口  
template <class Predicate>  
inline unary_negate<Predicate> not1(const Predicate& pred)  
{  
    return unary_negate<Predicate>(pred);  
}  
//测试程序  
int main()  
{  
    vector<int> vec(10, 1);  
    int count1 = 0, count2 = 0;  
    count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 10),count1);       //求容器中小于等于10的元素个数  
    count_if(vec.begin(), vec.end(), not1(bind2nd(less_equal<int>(), 10)),count2); //求容器中不小于等于10的元素个数,正好是上面函数的取反  
    cout<<count1<<' '<<count2<<endl;  //10 0  
    return 0;  
}    




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值