美文网首页
STL 算法

STL 算法

作者: wjundong | 来源:发表于2020-01-23 13:44 被阅读0次
    • 算法部分主要由头文件 <algorithm>,<numeric>和<functional>组成。
    • <algorithm>是所有STL头文件中最大的一个,其中常用到的功能范围涉及到比较、交换、查找、遍历操作、复制、修改、反转、排序、合并等等。
    • <numeric>体积很小,只包括几个在序列上面进行简单数学运算的模板函数,包括加法和乘法在序列上的一些操作。
    • <functional>中则定义了一些模板类,用以声明函数对象。
    • STL提供了大量实现算法的模版函数,只要我们熟悉了STL之后,许多代码可以被大大的化简,只需要通过调用一两个算法模板,就可以完成所需要的功能,从而大大地提升效率。

    STL中算法分类

    • 操作对象
      • 直接改变容器的内容
      • 将原容器的内容复制一份,修改其副本,然后传回该副本
    • 功能:
      • 非可变序列算法 指不直接修改其所操作的容器内容的算法
        • 计数算法 count、count_if
        • 搜索算法 search、find、find_if、find_first_of、…
        • 比较算法 equal、mismatch、lexicographical_compare
      • 可变序列算法 指可以修改它们所操作的容器内容的算法
        • 删除算法 remove、remove_if、remove_copy、…
        • 修改算法 for_each、transform
        • 排序算法 sort、stable_sort、partial_sort、
      • 排序算法 包括对序列进行排序和合并的算法、搜索算法以及有序序列上的集合操作
      • 数值算法 对容器内容进行数值计算

    算法统计

    • 查找算法(13个):判断容器中是否包含某个值

    • 堆算法(4个)

    • 关系算法(8个)

    • 集合算法(4个)

    • 列组合算法(2个)

    • 排序和通用算法(14个):提供元素排序策略

    • 删除和替换算法(15个)

    • 生成和变异算法(6个)

    • 算数算法(4个)

    常用算法汇总

    • 常用的查找算法:
      adjacent_find() //adjacent 是邻近的意思
      binary_search(), count(), count_if(), equal_range(), find(),find_if()
      
    • 常用的排序算法:
      merge(), sort(), random_shuffle() // shuffle是洗牌的意思 
      reverse()
      
    • 常用的拷贝和替换算法:
      copy(), replace(), replace_if(), swap()
      
    • 常用的算术和生成算法:
      accumulate() // accumulate 是求和的意思
      fill()
      
    • 常用的集合算法:
      set_union(),set_intersection(),set_difference()
      
    • 常用的遍历算法:
      for_each(), transform() //transform 是变换的意思
      

    常用的查找算法

    • adjacent_find ()
      在 iterator 对标识元素范围内,查找一对相邻重复元素,找到则返回指向这对元素的第一个元素的迭代器。否则返回 past-the-end

      void demo1()
      {
          vector<int> vecInt;
          vecInt.push_back(1);
          vecInt.push_back(2);
          vecInt.push_back(2);
          vecInt.push_back(4);
          vecInt.push_back(5);
          vecInt.push_back(5);
      
          vector<int>::iterator it = adjacent_find(vecInt.begin(), vecInt.end());
          //*it == 2
          if (it ==vecInt.end())
              cout << "not found" << endl;
          else
              cout << *it << endl;
      }
      
    • binary_search ()
      在有序序列中查找value,找到则返回true。注意:在无序序列中,不可使用

      void demo2()
      {
          // set 插入的时候就排好序了
          set<int> setInt;
          setInt.insert(3);
          setInt.insert(1);
          setInt.insert(7);
          setInt.insert(5);
          setInt.insert(9);
      
          bool bFind = binary_search(setInt.begin(),setInt.end(),5);
      
          if (bFind == 1)
              cout << "true" << endl;
          else
              cout << "false" << endl;
      }
      
    • count ()
      利用等于操作符,把标志范围内的元素与输入值比较,返回相等的个数

      void demo3()
      {
          vector<int> vecInt;
          vecInt.push_back(1);
          vecInt.push_back(2);
          vecInt.push_back(2);
          vecInt.push_back(4);
          vecInt.push_back(2);
          vecInt.push_back(5);
          int iCount = count(vecInt.begin(),vecInt.end(),2);  //iCount==3
      
          cout << iCount << endl;
      }   
      
    • count_if ()

      //先定义比较函数
      bool GreaterThree(int iNum) {
          return iNum >= 3 ? true : false;
      }
      
      template<typename T>
      class A {
      public:
          bool operator()(T iNum)  {
              return iNum >= 3 ? true : false;
          }
      };
      
      void demo4()
      {
          vector<int> vecInt;
          vecInt.push_back(1);
          vecInt.push_back(3);
          vecInt.push_back(5);
          vecInt.push_back(7);
          vecInt.push_back(9);
      
          A<int> a;
      
          //回调函数可以是GreaterThree、a、A<int>()
          int iCount = count_if(vecInt.begin(), vecInt.end(), A<int>());
      
          //此时iCount == 4
          cout << iCount << endl;
      }
      
    • find ()

      • find: 利用底层元素的等于操作符,对指定范围内的元素与输入值进行比较。当匹配时,结束搜索,返回该元素的迭代器
      • equal_range: 返回一对 iterator,第一个表示 lower_bound, 第二个表示 upper_bound
        void demo5() 
        {
            vector<int> vecInt;
            vecInt.push_back(1);
            vecInt.push_back(3);
            vecInt.push_back(5);
            vecInt.push_back(7);
            vecInt.push_back(9);
        
            vector<int>::iterator it = find(vecInt.begin(), vecInt.end(), 5);
            // *it = 5
            cout << *it << endl;
        }
        
    • find_if ()
      使用输入的函数代替等于操作符执行find。返回被找到的元素的迭代器

      //先定义比较函数
      bool GreaterThree(int iNum) {
          return iNum >= 3 ? true : false;
      }
      
      void demo6()
      {
          vector<int> vecInt;
          vecInt.push_back(1);
          vecInt.push_back(3);
          vecInt.push_back(5);
          vecInt.push_back(7);
          vecInt.push_back(9);
      
          vector<int>::iterator it =  find_if(vecInt.begin(), vecInt.end(), GreaterThree);
      
          // *it = 3
          cout << *it << endl;
      }
      

    常用的排序算法

    • merge ()
      合并两个有序序列,存放到另一个序列

      void demo7() 
      {
          vector<int> vecIntA;
          vecIntA.push_back(1);
          vecIntA.push_back(3);
          vecIntA.push_back(5);
          vecIntA.push_back(7);
          vecIntA.push_back(9);
      
          vector<int> vecIntB;
          vecIntB.push_back(2);
          vecIntB.push_back(3);
          vecIntB.push_back(6);
          vecIntB.push_back(7);
      
          vector<int> vecIntC;
          vecIntC.resize(vecIntA.size() + vecIntB.size());
          merge(vecIntA.begin(), vecIntA.end(), vecIntB.begin(), vecIntB.end(),vecIntC.begin());
      
      
          for(auto x : vecIntC)
              cout << x << endl;
      }
      
    • sort ()
      以默认升序的方式重新排列指定范围内的元素。若要改排序规则,可以输入比较函数。

      //学生类
      class CStudent
      {
      public:
          CStudent(int iID, string strName)
          {
              m_iID = iID;
              m_strName = strName;
          }
          friend bool Compare(const CStudent &stuA,const CStudent &stuB);
          friend void demo8();
      private:
          int m_iID;
          string m_strName;
      };
      
      //学号比较函数
      bool Compare(const CStudent &stuA, const CStudent &stuB)
      {
          return (stuA.m_iID < stuB.m_iID);
      }
      
      
      void demo8()
      {
          vector<CStudent> vecStu;
          vecStu.push_back(CStudent(2,"老二"));
          vecStu.push_back(CStudent(1,"老大"));
          vecStu.push_back(CStudent(3,"老三"));
          vecStu.push_back(CStudent(4,"老四"));
      
          
          sort(vecStu.begin(),vecStu.end(),Compare);
      
          // 此时,vecStu容器包含了按顺序的"老大对象","老二对象","老三对象","老四对象"
          for(auto x : vecStu)
              cout << x.m_iID << " " << x.m_strName << endl;
      }
      
    • random_shuffle ()
      对指定范围内的元素随机调整次序

      void demo9()
      {
          //设置随机种子
          srand(time(0));         
      
          vector<int> vecInt;
          vecInt.push_back(1);
          vecInt.push_back(3);
          vecInt.push_back(5);
          vecInt.push_back(7);
          vecInt.push_back(9);
      
          string str("helloworld");
      
          random_shuffle(vecInt.begin(), vecInt.end());   // 顺序容器随机排序,结果比如:9,7,1,5,3
          random_shuffle(str.begin(), str.end()); // 字符串随机排序,结果比如:"lolwoehlrd"       
      
          for(auto x : vecInt)
              cout << x << " ";
          cout << endl << str << endl;
      }
      
    • reverse ()

      void demo10()
      {
          vector<int> vecInt;
          vecInt.push_back(1);
          vecInt.push_back(3);
          vecInt.push_back(5);
          vecInt.push_back(7);
          vecInt.push_back(9);
      
          reverse(vecInt.begin(), vecInt.end());      //{9,7,5,3,1}
      
          for(auto x : vecInt)
              cout << x << endl;
      }
      

    常用的拷贝和替换算法

    • copy ()
      拷贝指定范围所有元素到新的容器

      void demo11()
      {
          vector<int> vecIntA;
          vecIntA.push_back(1);
          vecIntA.push_back(3);
          vecIntA.push_back(5);
          vecIntA.push_back(7);
          vecIntA.push_back(9);
      
          vector<int> vecIntB;
          vecIntB.resize(vecIntA.size());  //扩大空间
      
          copy(vecIntA.begin(), vecIntA.end(), vecIntB.begin());  //vecIntB: {1,3,5,7,9}
      
          for(auto x : vecIntB)
              cout << x << endl;
      }
      
    • replace ()

      replace(beg, end, oldValue, newValue)
      

      将指定范围内的所有等于 oldValue 的元素替换成 newValue

      void demo12()
      {
          vector<int> vecIntA;
          vecIntA.push_back(1);
          vecIntA.push_back(3);
          vecIntA.push_back(5);
          vecIntA.push_back(3);
          vecIntA.push_back(9);
      
          // 把所有为 3 的元素替换为 8 
          replace(vecIntA.begin(), vecIntA.end(), 3, 8); // {1,8,5,8,9}
      
          for(auto x : vecIntA)
              cout << x << endl;
      }
      
    • replace_if ()

      replace_if(vecIntA.begin(),vecIntA.end(),GreaterThree,newVal)
      

      将指定范围内所有操作结果为 true 的元素用新值替换。

    
    bool GreaterThree(int iNum) {
        return iNum >= 3 ? true : false;
    }
    
    void demo13()
    {
        vector<int> vecIntA;
        vecIntA.push_back(1);
        vecIntA.push_back(3);
        vecIntA.push_back(5);
        vecIntA.push_back(3);
        vecIntA.push_back(9);
    
        // 把大于等于 3 的元素替换成 8
        replace_if(vecIntA.begin(), vecIntA.end(), GreaterThree, 8);
    
        // 1 8 8 8 8
        for(auto x : vecIntA)
            cout << x << endl;
    }
    
    • swap ()
      交换两个容器的元素
      void demo14()
      {
          vector<int> vecIntA;
          vecIntA.push_back(1);
          vecIntA.push_back(3);
          vecIntA.push_back(5);
          
          vector<int> vecIntB;
          vecIntB.push_back(2);
          vecIntB.push_back(4);
      
          swap(vecIntA, vecIntB);  //交换
      }
      

    常用的算术和生成算法

    用到 #include <numeric>

    • accumulate ()
      对指定范围内的元素求和,然后结果再加上一个由 val 指定的初始值
      void demo15()
      {
          vector<int> vecIntA;
          vecIntA.push_back(1);
          vecIntA.push_back(3);
          vecIntA.push_back(5);
          vecIntA.push_back(7);
          vecIntA.push_back(9);
          int iSum = accumulate(vecIntA.begin(), vecIntA.end(), 100);     //iSum==125
          cout << iSum << endl;
      }
      
    • fill ()
      将输入值赋给标志范围内的所有元素
    void demo16()
    {
        vector<int> vecIntA;
        vecIntA.push_back(1);
        vecIntA.push_back(3);
        vecIntA.push_back(5);
        vecIntA.push_back(7);
        vecIntA.push_back(9);
        fill(vecIntA.begin(), vecIntA.end(), 8);        //8, 8, 8, 8, 8
    }
    

    常用的集合算法

    • set_union() 构造一个有序序列,包含两个有序序列的并集
    • set_intersection() 构造一个有序序列,包含两个有序序列的交集
    • set_difference() 构造一个有序序列,该序列保留第一个有序序列中存在而第二个有序序列中不存在的元素
    void demo17()
    {
        vector<int> vecIntA;
        vecIntA.push_back(1);
        vecIntA.push_back(3);
        vecIntA.push_back(5);
        vecIntA.push_back(7);
        vecIntA.push_back(9);
    
        vector<int> vecIntB;
        vecIntB.push_back(1);
        vecIntB.push_back(3);
        vecIntB.push_back(5);
        vecIntB.push_back(6);
        vecIntB.push_back(8);
    
        vector<int> vecIntC;
        vecIntC.resize(10);
    
        //并集
        //vecIntC : {1,3,5,6,7,8,9,0,0,0}
        set_union(vecIntA.begin(), vecIntA.end(), vecIntB.begin(), vecIntB.end(), vecIntC.begin());     
    
        //交集
        fill(vecIntC.begin(),vecIntC.end(),0);
        //vecIntC: {1,3,5,0,0,0,0,0,0,0}
        set_intersection(vecIntA.begin(), vecIntA.end(), vecIntB.begin(), vecIntB.end(), vecIntC.begin());      
    
        //差集
        fill(vecIntC.begin(),vecIntC.end(),0);
        //vecIntC: {7,9,0,0,0,0,0,0,0,0}
        set_difference(vecIntA.begin(), vecIntA.end(), vecIntB.begin(), vecIntB.end(), vecIntC.begin());
    }           
    

    常用的遍历算法

    • for_each ()
      用指定函数依次对指定范围内所有元素进行迭代访问。该函数不得修改序列中的元素

      void show(const int &iItem)
      {
          cout << iItem << " ";
      }
      
      void demo18()
      {
          int iArray[] = {0,1,2,3,4};
          vector<int> vecInt(iArray, iArray+sizeof(iArray)/sizeof(iArray[0]));
          for_each(vecInt.begin(), vecInt.end(), show);
          // 结果打印出0 1 2 3 4
      }
      
    • transform ()
      与 for_each 类似,遍历所有元素,但可对容器的元素进行修改

      int increase (int i)  
      {  
          return i+1;   
      }  
      
      void demo19()
      {
          vector<int> vecIntA;
          vecIntA.push_back(1);
          vecIntA.push_back(3);
          vecIntA.push_back(5);
          vecIntA.push_back(7);
          vecIntA.push_back(9);
      
      
          transform(vecIntA.begin(), vecIntA.end(), vecIntA.begin(), increase);       
          // vecIntA : {2,4,6,8,10}
      
          for(auto x : vecIntA)
              cout << x << endl;
      }
      

    STL 综合案例

    案例:学校演讲比赛

    • 某市举行一场演讲比赛,共有24个人参加,按参加顺序设置参赛号。比赛共三轮,前两轮为淘汰赛,第三轮为决赛。
    • 比赛方式:分组比赛
      • 第一轮分为4个小组,根据参赛号顺序依次划分,比如100-105为一组,106-111为第二组,依次类推,每组6个人,每人分别按参赛号顺序演讲。当小组演讲完后,淘汰组内排名最后的三个选手,然后继续下一个小组的比赛。
      • 第二轮分为2个小组,每组6人,每个人分别按参赛号顺序演讲。当小组完后,淘汰组内排名最后的三个选手,然后继续下一个小组的比赛。
      • 第三轮只剩下6个人,本轮为决赛,选出前三名。选手每次要随机分组,进行比赛。
    • 比赛评分:10个评委打分,去除最低、最高分,求平均分。每个选手演讲完由10个评委分别打分。该选手的最终得分是去掉一个最高分和一个最低分,求得剩下的8个成绩的平均分。选手的名次按得分降序排列,若得分一样,按参赛号升序排名。

    用STL编程,求解一下问题

    1. 请打印出所有选手的名字与参赛号,并以参赛号的升序排列。
    2. 打印每一轮比赛前,分组情况
    3. 打印每一轮比赛后,小组晋级名单
    4. 打印决赛前三名,选手名称、成绩。

    相关文章

      网友评论

          本文标题:STL 算法

          本文链接:https://www.haomeiwen.com/subject/qxsnzctx.html