STL 算法

  • 算法部分主要由头文件 组成。
  • 是所有STL头文件中最大的一个,其中常用到的功能范围涉及到比较、交换、查找、遍历操作、复制、修改、反转、排序、合并等等。
  • 体积很小,只包括几个在序列上面进行简单数学运算的模板函数,包括加法和乘法在序列上的一些操作。
  • 中则定义了一些模板类,用以声明函数对象。
  • 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 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::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 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 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
    class A {
    public:
        bool operator()(T iNum)  {
            return iNum >= 3 ? true : false;
        }
    };
    
    void demo4()
    {
        vector vecInt;
        vecInt.push_back(1);
        vecInt.push_back(3);
        vecInt.push_back(5);
        vecInt.push_back(7);
        vecInt.push_back(9);
    
        A a;
    
        //回调函数可以是GreaterThree、a、A()
        int iCount = count_if(vecInt.begin(), vecInt.end(), A());
    
        //此时iCount == 4
        cout << iCount << endl;
    }
    
  • find ()

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

常用的排序算法

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

    void demo7() 
    {
        vector vecIntA;
        vecIntA.push_back(1);
        vecIntA.push_back(3);
        vecIntA.push_back(5);
        vecIntA.push_back(7);
        vecIntA.push_back(9);
    
        vector vecIntB;
        vecIntB.push_back(2);
        vecIntB.push_back(3);
        vecIntB.push_back(6);
        vecIntB.push_back(7);
    
        vector 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 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 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 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 vecIntA;
        vecIntA.push_back(1);
        vecIntA.push_back(3);
        vecIntA.push_back(5);
        vecIntA.push_back(7);
        vecIntA.push_back(9);
    
        vector 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 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 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 vecIntA;
        vecIntA.push_back(1);
        vecIntA.push_back(3);
        vecIntA.push_back(5);
        
        vector vecIntB;
        vecIntB.push_back(2);
        vecIntB.push_back(4);
    
        swap(vecIntA, vecIntB);  //交换
    }
    

常用的算术和生成算法

用到 #include

  • accumulate ()
    对指定范围内的元素求和,然后结果再加上一个由 val 指定的初始值
    void demo15()
    {
        vector 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 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 vecIntA;
    vecIntA.push_back(1);
    vecIntA.push_back(3);
    vecIntA.push_back(5);
    vecIntA.push_back(7);
    vecIntA.push_back(9);

    vector vecIntB;
    vecIntB.push_back(1);
    vecIntB.push_back(3);
    vecIntB.push_back(5);
    vecIntB.push_back(6);
    vecIntB.push_back(8);

    vector 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 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 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 算法)