c++ stl常用算法

发布于:2025-06-05 ⋅ 阅读:(20) ⋅ 点赞:(0)

目录

1.算法介绍

算法概述

STL中算法分类

常用算法汇总

2.常用算法用法示例

遍历

for_each

transform

for_each和transform对比

查找

adjacent_find

binary_search

count

count_if

find

find_if

排序

merge

sort

random_shuffle

reverse

拷贝和替换

copy

replace

replace_if

swap

算术运算

accumulate

fill

集合运算


1.算法介绍

算法概述

  • 算法部分主要由头文件<algorithm>,<functional>和<numeric>组成。
    • <algorithm>是所有STL头文件中最大的一个,其中常用到的功能范围涉及到比较、交换、查找、遍历操作、复制、修改、反转、排序、合并等等。
    • <functional>中则定义了一些模板类,用以声明函数对象。
    • <numeric>体积很小,只包括几个在序列上面进行简单数学运算的模板函数,包括加法和乘法在序列上的一些操作。
  • 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、
    • 排序算法 包括对序列进行排序和合并的算法、搜索算法以及有序序列上的集合操作
    • 数值算法 对容器内容进行数值计算

常用算法汇总

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

2.常用算法用法示例

遍历

for_each

  • for_each:  用指定函数依次对指定范围内所有元素进行迭代访问。该函数不会修改序列中的元素。
  • 函数使用:for_each(begin, end, func);

for_each函数原型理解(注意返回类型, 注意_Function __f这里不是引用)

注意for_each的第三个参数 函数对象做函数参数,函数对象做返回值

template<class _InIt,
class _Fn1> inline
_Fn1 for_each(_InIt _First, _InIt _Last, _Fn1 _Func)
{ // perform function for each element
_DEBUG_RANGE(_First, _Last);
_DEBUG_POINTER(_Func);
return (_For_each(_Unchecked(_First), _Unchecked(_Last), _Func));
}

例子

#include <iostream>
#include <string>
#include <vector>
#include <list>

#include <algorithm>
#include <functional>

using namespace std;

template <typename T>
void printVec(vector<T> vec)
{
    auto it = vec.begin();
    for (it; it != vec.end(); it++)
    {
        cout << *it << "\t";
    }
    cout << endl;
}

template <typename T>
void printList(list<T> lst)
{
    auto it = lst.begin();
    for (it; it != lst.end(); it++)
    {
        cout << *it << "\t";
    }
    cout << endl;
}

void showElement(int n)
{
    cout << n << "\t";
}

class MyShow
{
public:
    MyShow()
    {
        num = 0;
    }
    void operator()(int n)
    {
        num++;
        cout << n << "\t";
    }
    void printNum()
    {
        cout << "num=" << num << endl;
    }
protected:
private:
    int num;
};

void test()
{
    vector<int> v1 = {1, 3, 5};
    printVec(v1);

    // 1.for_each算法对接普通回调函数
    for_each(v1.begin(), v1.end(), showElement);
    cout << endl;

    // 2.for_each算法对接匿名函数对象
    for_each(v1.begin(), v1.end(), MyShow());
    cout << endl;

    // 3.for_each算法对接函数对象
    MyShow myshow;
    MyShow temp_myshow = for_each(v1.begin(), v1.end(), myshow);
    cout << endl;
    // 查看myshow运算符()的调用次数
    myshow.printNum();         // 0
    temp_myshow.printNum();    // 3

    temp_myshow = for_each(v1.begin(), v1.end(), myshow);
    cout << endl;
    temp_myshow.printNum();    // 3

}

int main()
{
    // test for for_each
    test();

    return 0;
}

transform

transform:   与for_each类似,遍历所有元素,但可对容器的元素进行修改

transform()算法有两种形式:

第一种:transform(b1, e1, b2, op) 。可以一个容器的元素,通过op,变换到另一个容器中(同一个容器中)。将b1到e1中的每个元素通过op函数操作后的返回值从b2位置开始替换

第二种:transform(b1, e1, b2, b3, op) 。也可以把两个容器的元素,通过op,变换到另一个容器中

函数原型1

template<class _InIt,
class _OutIt,
class _Fn1> inline
_OutIt transform(_InIt _First, _InIt _Last, _OutIt _Dest, _Fn1 _Func)

函数原型2

template<typename _InputIterator, typename _OutputIterator,
     typename _UnaryOperation>
    _OutputIterator
    transform(_InputIterator __first, _InputIterator __last,
        _OutputIterator __result, _UnaryOperation __unary_op)
    {
      // concept requirements
      __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
      __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator,
      // "the type returned by a _UnaryOperation"
      __typeof__(__unary_op(*__first))>)
      __glibcxx_requires_valid_range(__first, __last);

      for (; __first != __last; ++__first, (void)++__result)
  *__result = __unary_op(*__first);
      return __result;
    }

例子

#include <iostream>
#include <string>
#include <vector>
#include <list>

#include <algorithm>
#include <functional>
#include "iterator"

using namespace std;

template <typename T>
void printVec(vector<T> vec)
{
    auto it = vec.begin();
    for (it; it != vec.end(); it++)
    {
        cout << *it << "\t";
    }
    cout << endl;
}

template <typename T>
void printList(vector<T> lst)
{
    auto it = lst.begin();
    for (it; it != lst.end(); it++)
    {
        cout << *it << "\t";
    }
    cout << endl;
}

int increase(int i)
{
    return i + 100;
}

void test()
{
    vector<int> v1 = {1, 3, 5};
    printVec(v1);   // 1    3   5

    // 1.transform算法使用自定义的回调函数
    vector<int> v2;
    v2.resize(v1.size());
    transform(v1.begin(), v1.end(), v2.begin(), increase);
    printVec(v1);  // 1 3   5
    printVec(v2);  // 101   103 105

    // 2.transform算法修改容器本身
    transform(v1.begin(), v1.end(), v1.begin(), increase);
    printVec(v1);  // 101   103 105

    // 3.transform算法 使用 预定义的函数对象
    transform(v1.begin(), v1.end(), v1.begin(), negate<int>());
    printVec(v1);  // -101  -103    -105

    // 4.transform算法 使用函数适配器和函数对象
    transform(v1.begin(), v1.end(), v1.begin(), bind2nd(multiplies<int>(), 10));
    printVec(v1);  // -1010 -1030   -1050

    // 5.transform也可以把结果输出到屏幕上而不是输出到其它容器中
    // 注意头文件 "iterator"
    transform(v1.begin(), v1.end(), ostream_iterator<int>(cout, "\t"), negate<int>());
    // 屏幕会打印:1010   1030    1050
    cout << endl;
    printVec(v1);  // -1010 -1030   -1050

}

int main()
{
    // test for for_each
    test();

    return 0;
}

for_each和transform对比

  • ①使用比较
    • 一般情况下:for_each所使用的函数对象,参数是引用,没有返回值
void mysquare(int &num)
{
    num = num * num;
}
    • transform所使用的函数对象,参数一般不使用引用,而是还有返回值
int mysquare2(int num) //结果的传出,必须是通过返回值
{
    return num = num * num;
}
  • ②速度和灵活度比较
    • for_each() 速度快 用法不灵活
    • transform() 速度慢 用法非常灵活

函数原型

 template<typename _InputIterator, typename _Function>
    _Function
    for_each(_InputIterator __first, _InputIterator __last, _Function __f)
    {
      // concept requirements
      __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
      __glibcxx_requires_valid_range(__first, __last);
      for (; __first != __last; ++__first)
  __f(*__first);
      return __f; // N.B. [alg.foreach] says std::move(f) but it's redundant.
    }

  template<typename _InputIterator, typename _OutputIterator,
     typename _UnaryOperation>
    _OutputIterator
    transform(_InputIterator __first, _InputIterator __last,
        _OutputIterator __result, _UnaryOperation __unary_op)
    {
      // concept requirements
      __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
      __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator,
      // "the type returned by a _UnaryOperation"
      __typeof__(__unary_op(*__first))>)
      __glibcxx_requires_valid_range(__first, __last);

      for (; __first != __last; ++__first, (void)++__result)
  *__result = __unary_op(*__first);
      return __result;
    }

代码示例理解

#include <iostream>
#include <string>
#include <vector>

#include <algorithm>
#include <functional>

using namespace std;

template <typename T>
void printVec(vector<T> vec)
{
    auto it = vec.begin();
    for (it; it != vec.end(); it++) {
        cout << *it << "\t";
    }
    cout << endl;
}

void showElement(int &n)
{
    cout << n << "\t";
    n = n * 2;
    // 无返回值
}

int showElement2(int n)
{
    cout << n << "\t";
    return n;  // 注意有返回值
}

void test()
{
    vector<int> v1 = {1, 3, 5};
    vector<int> v2 = v1;

    // 一般情况下:for_each所使用的函数对象,参数是引用,没有返回值
    for_each(v1.begin(), v1.end(), showElement);   // 1 3   5
    cout << endl;   
    printVec(v1);  // 2 6   10
    cout << endl;  

    // transform所使用的函数对象,参数一般不使用引用,而是还有返回值
    transform(v2.begin(), v2.end(), v2.begin(), showElement2);  // 1    3   5
    cout << endl;
    printVec(v2);  // 1 3   5
}

int main()
{
    // test for for_each
    test();

    return 0;
}

查找

adjacent_find

在iterator对标识元素范围内,查找一对相邻重复元素,找到则返回指向这对元素的第一个元素的迭代器。否则返回迭代器尾部。

#include <iostream>
#include <vector>

#include <algorithm>
#include <functional>

using namespace std;

void test()
{
    std::vector<int> v1 = {1, 2, 2, 3, 5};
    std::vector<int>::iterator it = adjacent_find(v1.begin(), v1.end());
    if (it == v1.end()) {
        cout << "未找到相邻相同元素" << endl;
    } else {
        cout << "找到相邻相同元素" << endl;
        cout << "第一个数:" << *it << endl;
        it++;
        cout << "第二个数:" << *it << endl;
    }

}

int main()
{
    test();
    return 0;
}

在有序序列中查找value,二分查找,找到则返回true。

注意:在无序序列中,不可使用。

#include <iostream>
#include <vector>

#include <algorithm>
#include <functional>

using namespace std;

void test()
{
    std::vector<int> v1 = {1, 3, 5, 7, 9};
    bool ret_bool = binary_search(v1.begin(), v1.end(), 7);
    if (ret_bool) {
        cout << "找到了" << endl;
    } else {
        cout << "未找到" << endl;
    }

}

int main()
{
    test();
    return 0;
}

count

利用等于操作符,把标志范围内的元素与输入值比较,返回相等的个数。

#include <iostream>
#include <vector>

#include <algorithm>
#include <functional>

using namespace std;

void test()
{
    std::vector<int> v1 = {1, 3, 5, 7, 7, 9, 7};
    int num = count(v1.begin(), v1.end(), 7);
    cout << num << endl;  // 3

}

int main()
{
    test();
    return 0;
}

count_if

自定义返回值为bool类型的函数,统计个数返回true的个数

#include <iostream>
#include <vector>

#include <algorithm>
#include <functional>

using namespace std;

// 是否是3的倍数
bool div_three(int num)
{
    if (num - num / 3 * 3 == 0) {
        return true;
    }
    return false;
}

void test()
{
    vector<int> v1 = {1, 3, 5, 7, 7, 9, 7};
    int num = count_if(v1.begin(), v1.end(), div_three);
    cout << num << endl;  // 2
}

int main()
{
    test();
    return 0;
}

find

find:  利用底层元素的等于操作符,对指定范围内的元素与输入值进行比较。当匹配时,结束搜索,返回该元素的迭代器。

#include <iostream>
#include <vector>

#include <algorithm>
#include <functional>

using namespace std;

void test()
{
    vector<int> v1 = {1, 3, 5, 7, 7, 9, 7};
    vector<int>::iterator it = find(v1.begin(), v1.end(), 5);
    if (it == v1.end()) {
        cout << "not found" << endl;
    } else {
        cout << *it << endl;  // 5
    }

}

int main()
{
    test();
    return 0;
}

find_if

find_if:   使用输入的函数代替等于操作符执行find。返回被找到的元素的迭代器。

#include <iostream>
#include <vector>

#include <algorithm>
#include <functional>

using namespace std;

// 是否是3的倍数
bool div_three(int num)
{
    if (num - num / 3 * 3 == 0) {
        return true;
    }
    return false;
}

void test()
{
    vector<int> v1 = {1, 3, 5, 7, 7, 9, 7};

    // 第一个能整除3的位置
    vector<int>::iterator it = find_if(v1.begin(), v1.end(), div_three);
    if (it == v1.end()) {
        cout << "not found" << endl;
    } else {
        cout << *it << endl;  // 3
        it++;
        cout << *it << endl;  // 5
    }

}

int main()
{
    test();
    return 0;
}

排序

merge

merge:    合并两个有序序列,存放到另一个序列(自动排序)。

#include <iostream>
#include <vector>

#include <algorithm>
#include <functional>

using namespace std;

void printV(vector<int> vec)
{
    for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++) {
        cout << *it << "\t";
    }
    cout << endl;
}

void test()
{
    vector<int> v1 = {1, 3, 7};
    vector<int> v2 = {2, 4, 5, 6};

    vector<int> v3;
    v3.resize(v1.size() + v2.size());

    merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
    printV(v3);  // 1   2   3   4   5   6   7
}

int main()
{
    test();
    return 0;
}

sort

sort:  以默认升序的方式重新排列指定范围内的元素。若要改排序规则,可以输入比较函数。

#include <iostream>
#include <vector>

#include <algorithm>
#include <functional>

using namespace std;

class Student
{
public:
    Student(string name, int id)
    {
        m_name = name;
        m_id = id;
    }
    void printT()
    {
        cout << "name:" << m_name << "\tid:" << m_id << endl;
    }
protected:
public:
    string m_name;
    int m_id;

};

// sort函数会改变容器的值,所以这里用引用
bool CompareStudent(Student &stu1, Student &stu2)
{
    return (stu1.m_id < stu2.m_id);  // 升序
}

void test()
{
    Student s1("老大", 1);
    Student s2("老二", 2);
    Student s3("老三", 3);
    Student s4("老四", 4);

    vector<Student> v1;
    v1.push_back(s4);
    v1.push_back(s1);
    v1.push_back(s3);
    v1.push_back(s2);

    for (vector<Student>::iterator it = v1.begin(); it != v1.end(); it++){
        it->printT();
    }
    /*
    name:老四 id:4
    name:老大 id:1
    name:老三 id:3
    name:老二 id:2
    */

   // sort 根据自定义的函数进行排序
   sort(v1.begin(), v1.end(), CompareStudent);
    for (vector<Student>::iterator it = v1.begin(); it != v1.end(); it++) {
        it->printT();
    }
    /*
    name:老大 id:1
    name:老二 id:2
    name:老三 id:3
    name:老四 id:4
    */

}

int main()
{
    test();
    return 0;
}

random_shuffle

srand(time(0)); //设置随机种子

random_shuffle:     对指定范围内的元素随机调整次序。

#include <iostream>
#include <vector>

#include <stdlib.h>  // srand需要
#include <ctime>  // time(0)需要

#include <algorithm>
#include <functional>

using namespace std;

void printV(vector<int> vec)
{
    for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
    {
        cout << *it << "\t";
    }
    cout << endl;
}

void test()
{
    vector<int> v1 = {1, 3, 5, 7};

    // 设置随机数种子
    srand(time(0)); // 注意不设随机数种子的话,每次乱序的结果是一样

    random_shuffle(v1.begin(), v1.end());
    printV(v1);  

    string str = "abcdefg";
    random_shuffle(str.begin(), str.end());
    cout << str << endl;

    

}

int main()
{
    test();
    return 0;
}

reverse

反转

#include <iostream>
#include <vector>

#include <algorithm>
#include <functional>

using namespace std;

void printV(vector<int> vec)
{
    for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
    {
        cout << *it << "\t";
    }
    cout << endl;
}

void test()
{
    vector<int> v1 = {1, 3, 5, 7};

    reverse(v1.begin(), v1.end());

    printV(v1);  // 7   5   3   1
    

}

int main()
{
    test();
    return 0;
}

拷贝和替换

copy

拷贝

#include <iostream>
#include <vector>

#include <algorithm>
#include <functional>

using namespace std;

void printV(vector<int> vec)
{
    for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
    {
        cout << *it << "\t";
    }
    cout << endl;
}

void test()
{
    vector<int> v1 = {1, 3, 5, 7};

    vector<int> v2;
    v2.resize(v1.size());

    copy(v1.begin(), v1.end(), v2.begin());

    printV(v2);  // 1   3   5   7
    

}

int main()
{
    test();
    return 0;
}

replace

replace(beg, end, oldValue, newValue):    将指定范围内的所有等于oldValue的元素替换成newValue。

#include <iostream>
#include <vector>

#include <algorithm>
#include <functional>

using namespace std;

void printV(vector<int> vec)
{
    for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
    {
        cout << *it << "\t";
    }
    cout << endl;
}

void test()
{
    vector<int> v1 = {1, 3, 5, 7, 3};

    replace(v1.begin(), v1.end(), 3, 9);

    printV(v1);  // 1   9   5   7   9
    

}

int main()
{
    test();
    return 0;
}

replace_if

满足条件则替换为指定值

#include <iostream>
#include <vector>

#include <algorithm>
#include <functional>

using namespace std;

void printV(vector<int> vec)
{
    for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
    {
        cout << *it << "\t";
    }
    cout << endl;
}

// 是否大于等于5
bool great_equal_5(int &n)
{
    if (n >= 5)
    {
        return true;
    }
    return false;
}

void test()
{
    vector<int> v1 = {1, 3, 5, 7, 3};

    // 如果great_equal_5函数返回真,则替换为100
    replace_if(v1.begin(), v1.end(), great_equal_5, 100);

    printV(v1);  // 1   3   100 100 3
    

}

int main()
{
    test();
    return 0;
}

swap

swap:   交换两个容器的元素

#include <iostream>
#include <vector>

#include <algorithm>
#include <functional>

using namespace std;

void printV(vector<int> vec)
{
    for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
    {
        cout << *it << "\t";
    }
    cout << endl;
}

void test()
{
    vector<int> v1 = {1, 3, 5};
    vector<int> v2 = {2, 4, 6, 8};
    
    swap(v1, v2);

    printV(v1);  // 2   4   6   8
    printV(v2);  // 1   3   5

}

int main()
{
    test();
    return 0;
}

算术运算

accumulate

  • accumulate:  对指定范围内的元素求和,然后结果再加上一个由val指定的初始值。
  • #include <numeric>
#include <iostream>
#include <vector>

#include <algorithm>
#include <functional>
#include <numeric>

using namespace std;

void test()
{
    vector<int> v1;
    v1.push_back(1);
    v1.push_back(3);
    v1.push_back(5);
    int tmp = accumulate(v1.begin(), v1.end(), 100);
    cout << tmp << endl;  // 109

}

int main()
{
    test();
    return 0;
}

fill

fill: 将输入值赋给标志范围内的所有元素

#include <iostream>
#include <vector>

#include <algorithm>
#include <functional>

using namespace std;

void printV(vector<int> vec)
{
    for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
    {
        cout << *it << "\t";
    }
    cout << endl;
}


void test()
{
    vector<int> v1 = {1, 3, 5, 7, 9};

    auto it_start = v1.begin();
    it_start++;

    auto it_end = v1.end();
    it_end--;

    fill(it_start, it_end, 8);
    printV(v1);  // 1   8   8   8   9

}

int main()
{
    test();
    return 0;
}

集合运算

set_union(),set_intersection(),set_difference()

  • set_union:  构造一个有序序列,包含两个有序序列的并集。
  • set_intersection:  构造一个有序序列,包含两个有序序列的交集。
  • set_difference:  构造一个有序序列,该序列保留第一个有序序列中存在而第二个有序序列中不存在的元素。
#include <iostream>
#include <vector>

#include <algorithm>
#include <functional>

using namespace std;

void printV(vector<int> vec)
{
    for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
    {
        cout << *it << "\t";
    }
    cout << endl;
}

void test()
{
    vector<int> v1;
    v1.push_back(1);
    v1.push_back(3);
    v1.push_back(5);

    vector<int> v2;
    v2.push_back(2);
    v2.push_back(4);
    v2.push_back(6);

    vector<int> v3;
    v3.resize(v1.size() + v2.size());

    // 并集
    set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
    printV(v3);  // 1   2   3   4   5   6

    // 交集
    fill(v3.begin(), v3.end(), 0);
    set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
    printV(v3);  // 0   0   0   0   0   0

    // 差集
    fill(v3.begin(), v3.end(), 0);
    set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
    printV(v3);  // 1   3   5   0   0   0
}

int main()
{
    test();
    return 0;
}


end


网站公告

今日签到

点亮在社区的每一天
去签到