• 4_STL设计理念_算法


    STL算法,容器,迭代器的设计理念
    1.STL容器通过 类模板 技术,实现 数据类型 和 容器模型的分离;
    2.迭代器技术 实现了 遍历和操作容器的统一方法
    3.STL算法设计理念:通过预定义的函数对象函数对象实现了数据类型与算法的分离;预定义函数对象处理基本数据类型函数对象实现了自定义数据类型与算法的分离;
    核心思想:函数对象本质是回调函数;
    回调函数的思想:实现任务的编写者 和 任务的调用者有效解耦合。

    一、STL算法的设计理念

    函数对象
    一元函数对象、一元谓词
    二元函数对象、二元谓词
    预定义函数对象
    函数适配器
    容器算法迭代器的设计理念:
    要点:分清楚STL算法返回的值是迭代器 还是 谓词(函数对象)

    transform算法的输入,通过迭代器first和last指向的元素作为输入;通过result作为输出;
    通过函数对象来做自定义数据类型的运算。

    函数对象:重载函数调用操作符的类,其对象常称为函数对象。

    他们是行为类似函数的对象,通过:对象名(参数列表)。又称为仿函数,伪函数;
    通过重载类的 operator()来实现的。
    一元函数对象:函数参数为1个的函数对象
    二元函数对象:函数参数为2个

    谓词可以是一个仿函数,也可以是一个回调函数

    一元谓词 函数参数1个,函数返回值为bool类型
    二元谓词 函数参数2个,函数返回值为bool类型

    函数对象与普通函数的异同点:

    1.调用方式的相似性 

    template <typename T>
    class ShowElement
    {
    public:
      void operator()(T &t)   //重载了函数调用操作符的类 定义的对象 叫 函数对象
      {
        cout << t << " ";
      }
    protected:
    private:
    };
    template
    <typename T> //函数模板 void FuncShowElement(T &t) {   cout << t << endl; }
    void FuncShowElement(int &t) //普通函数 {   cout << t << endl; }
    void main() {   int a = 10;   ShowElement<int>showElement;   showElement(a); //函数对象的()执行,很像一个函数,是一个仿函数   FuncShoeElement<int>(a); //函数模板   FuncShoeElement(a); //普通函数 }

    不同点:函数对象的优势:

    函数对象是 类对象,能保持调用状态信息

    vector<int>v1;
    v1.push_back(1);
    v1.push_back(3);
    v1.push_back(5);
    
    for_each(v1.begin(),v1.end(),ShowElement<int>()); //匿名函数对象 匿名仿函数
    for_each(v1.begin(),v1.end(),FuncShowElement); //通过回调函数

    for_each算法中 :

    函数对象的两种用法:

    函数对象做函数参数
    函数对象当返回值


    for_each算法的 函数对象 是元素 即值传递,不是引用传递。但返回的是一个元素,可以通过返回值记录状态

    ShowElement<int>show;
    show = for_each(v1.begin(),v1.end(),show);//里面show是实参,左值是返回值
    show.printN();

    一元谓词和STL算法配合使用

    template<typename T> 
    class isDiv
    {
    public:
      isDiv(const T& divisor) //拷贝构造函数
      {
        this->divisor = divisor;
      }
      bool operator()(T& t)
      {
        return (t % divisor == 0);
      }
    protected:
    private:
      T divisor;
    }
    void main()
    {
      vector<int>v2;
      for(int i = 10; i < 33; i++)
      {
        v2.push_back(i);
      }
      int a = 4;
      isDiv<int>myDiv(a);
      //find_if(v2.begin(),v2.end(),myDiv);
      vector<int>::iterator it;
      it = find_if(v2.begin(),v2.end(),isDiv<int>(a));
      if(it == v2.end())
      {
        cout << "容器中没有被4整除的元素" << endl;
      }
      else
      {
        cout << "第一个被4整除的元素: " << *it <<endl;
      }
    }
    //查看源码,find_if返回的是迭代器;

    二元函数对象,二元谓词:

    两个数的比较,加和等;transform();

    template<typename T>
    class sumAdd
    {
    public:
      T operator()(T t1,T t2)
      {
        return t1+t2;
      }
    }    
    void main()
    {
      vector<int>v1,v2;
      vector<int>v3;
      v1.push_back(1);
      v1.push_back(2);
      v1.push_back(3);
    
      v2.push_back(4);
      v2.push_back(5);
      v2.push_back(6);
    
      v3.resize(10);
    //前两个参数是一个容器的迭代器参与运算的起点和终点,第三个参数是另一个容器的参与运算的开始位置;
    //第四个参数是结果存放的位置(可以是v1),第五个参数是函数对象(自己实现业务功能)
    //返回值是 第四个参数,即 存放结果的迭代器
      transform(v1.begin(),v1.end(),v2.begin(),v3.begin(),sumAdd<int>());
    }

    二元谓词:(比较大小)

    bool myCompre(const int& a,const int& b)
    {
      retrun a < b; //从小到大排序
    }
    void main() {   vector<int>v(10);   for(int i = 0; i < 10; i++)   {     int tmp = rand()%100;     v[i] = tmp;   }   sort(v.begin(),v.end(),myCompare); }

    二元谓词在set集合中的应用:

    find默认区分大小写,利用二元谓词让其不区分大小写;

    struct compareNoCase
    {
      bool operator()(const string& str1,const string& str2)
      {
        string str1_;
        str1_.resize(str1.size());
        transform(str1.begin(),str1,end(),str1_.begin(),tolower);
        string str2_;
        str2_.resize(str2.size());
        transform(str2.begin(),str2.end(),str2_.begin(),tolower)
        return (str1_ < str2_);
      }
    }
    
    set<string,compareNoCase>::iterator it = set1.find("aAa");//find函数默认区分大小写
    //利用仿函数的set实现了内容全部转化为小写,排序;其内部函数,insert()和find()的()已被重载,都有转化为小写的功能;

    预定义函数对象和函数适配器

    #include <functional>

    plus<int>add; //两个整形数相加
    plus<string>add; //字符串连接
    
    sort(v1.begin(),v1.end(),greater<string>());//加谓词后,从大到小排序
    
    //统计出现次数:
    //equal_to<string>()有两个参数:left参数来自容器,right参数来自sc
    //bind2nd是函数适配器;把预定义函数对象 和 第二个参数进行绑定
    string sc = "ccc";
    int num = count_if(v1.begin(),v1.end(),bind2nd(equal_to<string>(),sc)); //bind1st( , );

    函数适配器:

    STL中已经定义了大量函数对象,但有时候需要对函数返回值进行进一步简单计算,或者填上多余参数,不能直接代入算法。
    函数适配器将一种函数对象转化为另一种符合要求的函数对象。
    绑定适配器,组合适配器,指针函数适配器,成员函数适配器。

    binder1st:将数值绑定到二元函数的第一个参数,适配成一元函数    //bind1st(op,value)
    binder2nd:将数值绑定到二元函数的第二个参数,适配成一元函数    //bind2nd(op,value)
    unary_negate:将一元谓词的返回值适配成其逻辑反    //not1(op)
    binary_negate:将二元谓词的返回值适配成其逻辑反    //not2(op)
    
    int num = count(v1.begin(),v1.end(),3); //统计v1中3的个数
    
    //通过 谓词 求大于2的个数
    class isGreat
    {
    public:
      isGreat(int i)
      {
        m_num = i;
      }
      bool operator()(int& num)
      {
        if(num > m_num)
          return true;
        else 
          return false;
      }
    private:
    int m_num;
    };
    int num1 = count_if(v1.begin(),v1.end(),isGreat(2)); //通过预定义函数对象 求大于2的个数 int num2 = count_if(v1.begin(),v1.end(),bind2nd(greater<int>(),2)); //求 奇数个数 int num3 = count_if(v1.begin(),v1.end(),bind2nd(modulus<int>(),2)); int num4 = count_if(v1.begin(),v1.end(),not1(bind2nd(modulus<int>(),2)));



  • 相关阅读:
    checkbox 全选与全消
    sql server 关联和一些函数
    checkbox 判断是否选择
    sql 总结
    前台写逻辑
    android应用开发——popupWindow非全屏显示
    整理PostgreSQL数据库占用磁盘空间
    PHP常用的几个函数
    MySQL,PostgreSQL系统表(确认配置是否生效)
    Linux,查看目录大小
  • 原文地址:https://www.cnblogs.com/Lunais/p/5851051.html
Copyright © 2020-2023  润新知