C++小点之范型算法自定义比较函数的五种方法

零:使用STL自带的函数(less与greater)

    vector<int> v{45,2,5,8454,34,68421,5,84,1,5};

    sort(v.begin() ,v.end(),less<int>());//从小到大
    sort(v.begin() ,v.end(),greater<int>());///从大到小

一:普通比较函数

假设有一个vector<<\string>>,你的任务是统计长度小于5的string的个数,如果使用count_if 函数的话,代码就是这样:

bool LengthIsLessThanFive(const string& str) {
     return str.length() < 5;    
}
int res=count_if(vec.begin(), vec.end(), LengthIsLessThanFive);

二:函数对象类,也就是仿函数

我们继续沿着上一题增加要求,这里我们要求字符串的长度必须在一个区间,而且这个区间人为指定 ,那么我们就可以写成这样:

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
class fun
{
public:
    explicit fun(const int& l ,const int &h ):low(l),high(h) { }
    bool  operator()(const string &s) const {
        return s.length() > low && s.length() < high ; 
    }
private:
    const  int high ;
    const  int  low  ;
};
int main(void){
   std::vector<string> v{"11","2222222","3","44444444","555","66","777777"} ;//长度分别为 2,7,1,8,3,2,6
   int ll,hh  ;
   cin >> ll >> hh ; // 输入1,6 时,num== 3 。输入2,3,num== 0
   int num = count_if(v.begin(),v.end(),fun(ll,hh)); 
   cout << "num ==" << num  << endl ;  
    return 0 ;
}

这个我们来进行一点小小的总结:

***** 1.仿函数解决了一元或者二元谓词不能传入更多参数的尴尬
***** 2.能存储或者处理更多我们需要的有用信息

三:lambda (其实也是一种函数对象啦)

既然它也是一种函数对象,那么它就拥有函数对象的特征(解决了一元或者二元谓词不能传入更多参数的尴尬),这里我们还是要求字符串的长度必须在一个区间,而且这个区间人为指定,并且打印该区间内的单词 .



#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
int main(void){
   std::vector<string> v{"11","2222222","3","44444444","555","66","777777"} ;
   //  长度分别为2,7,1,8,3,2,6
   stable_sort(v.begin() ,v.end() ,[](const string &a ,const string &b){
        return a.size() < b.size() ;
   }); //先按照字符串长度进行排序

   for_each(v.begin(),v.end() ,[](const string &s ){
            cout << s << "  ";
   }) ;
   cout << endl ;


    int ll,hh  ;
   cin >> ll >> hh ; 
   auto  num  = count_if(v.begin(),v.end(),[ll,hh ]( const string &a ) {
        return a.size() > ll && a.size() < hh  ;
   }); 
   cout << "num ==" << num  << endl ;  

    //找到比  ll 大的第一个字符串
   auto  p1 = find_if(v.begin(),v.end(),[ll]( const string &a ) {
        return a.size() >  ll  ;
   }); 

   //找到比 hh 大 或者等于 的第一个字符串
   auto  p2 = find_if(v.begin(),v.end(),[hh]( const string &a ) {
       return a.size()  >= hh   ;//注意这里必须是 >=  号
   }); 
   for_each(p1,p2,[](const string &s ){ //打印
            cout << s << "  ";
   }) ;
   cout << endl ;
    return 0 ;
}

四:使用标准库bind函数

要求和前面一样,自己输入字符串的大小范围,找到有多少个字符串满足要求,输出即可 。

#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
using namespace std;
//bool fun2(const string &s ,string::size_type &l,string::size_type &h ){ 
bool fun2(const string &s ,string::size_type l,string::size_type h,string::size_type temp){
    return s.size() < h && s.size() > l ;
}
bool fun1(const string &s ,std::string::size_type l ){
    return s.size() < l  ;
}
int main(void) {
    using namespace std::placeholders ;//使用该命名空间,使得书写_1,_2,_n 时不需要书写"std::placeholders::_1 "
    std::vector<string> v{"11","2222222","3","44444444","555","66","777777"} ;//长度分别为 2,7,1,8,3,2,6
    int num1= count_if(v.begin(),v.end() ,bind(fun1,_1,6 ) );
    cout << num1  << endl ;
    cout << "please input the length of the string's range : "   ;
    string::size_type ll,hh ;
    cin >> ll >> hh  ;
    int num2= count_if(v.begin(),v.end() ,bind(fun2,_1,ll,hh,5555 ));
    cout << num2  << endl ; 
}

小结:

1. string::size_type 是一种无符号类型的值,并且能够存放的下任何string对象的大小,是string的size函数返回的变量 。在传参数的时候要注意,如果函数是这样子的:

bool fun2(const string &s ,
string::size_type &l,
string::size_type &h,
string::size_type &temp);

在传参数的时候就必须传入string::size_type 类型的变量,如果传入int类型就会出现比较奇葩的现象。也就是说如果有了size()函数的话就不要再使用int 了啦 !!

2.

bool fun2(const string &s ,
string::size_type temp);
count_if(v.begin(),v.end() ,bind(fun2,_1,ll,hh,5555 ));

_1 参数就是所遍历的这个vector ,后边的参数对应进行绑定即可

3. using namespace std::placeholders; 使用该命名空间,使得书写_1,_2,_n 时不需要书写”std::placeholders::_1 。也就是说_1,_2,_n 都在该命名空间之下 。

4.更多用法,点这里:http://en.cppreference.com/w/cpp/utility/functional/bind

这里写图片描述

五:重载 < 运算符

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std ;
class my_class{
public:
    my_class(const string &temp_name ,const int temp_value ):name(temp_name),value(temp_value){ }
    bool  operator<(const my_class & tt ) const {
        return this->value < tt.value  ;
    }
    string name ;
    int value ;
};
int main(void){
    my_class a[8]={{"赵",3},{"钱",5},{"宋",1},{"李",7},{"张",6},{"刘",9},{"王",456},{"龙",0}} ;
    sort(a,a+8);
    for(int i=0;i< 8 ;i++ ) 
        cout << a[i].name << " : " << a[i].value << endl ;
    return 0 ;
}

总结:

当需要自定义比较函数时,如果以后的操作比较都是固定的,就可以用重载,否则还是用普通函数,仿函数或者bind 函数 。(至于用哪个具体的还是要看个人喜好了。但我个人觉得bind更好用,你觉得呐??嘻嘻)

posted @ 2018-05-24 18:05  Tattoo_Welkin  阅读(133)  评论(0编辑  收藏  举报