• 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更好用,你觉得呐??嘻嘻)

  • 相关阅读:
    cpu核数和逻辑个数的区别_CPU逻辑核心数和物理核心数
    linux查看CPU数
    Java读取excel中日期格式结果为数字44326天
    Java实现读取excel中的数据及图片
    jmeter设置全局变量,获取登录token,实现两个线程组参数公用
    CPU使用率
    快照版本和发布版本区别
    jmeter与postman请求结果返回不一致
    接口认证方式:Bearer Token
    jmeter 中报java.lang.OutOfMemoryError: Java heap space
  • 原文地址:https://www.cnblogs.com/Tattoo-Welkin/p/10335291.html
Copyright © 2020-2023  润新知