STL

算法就是一种函数模板,C++中的算法是通过迭代器和模板来实现的,简单来说算法就是一系列的计算步骤,用来将输入数据转化成输出结果。

参考网站:1,2
补充网站:1,2,3

包括的头文件

1
2
3
#include <algorithm>
#include <numeric>
#include <functional>

算法的分类

  • 非可变序列算法
  • 可变序列算法
  • 排序算法
  • 数值算法

遍历算法

for_each
  • 用法:实现数组或集合的遍历
  • first:开始的迭代器
  • last:结束的迭代器
  • f:传入的函数
  • 可能的实现:

    1
    2
    3
    4
    5
    6
    7
    8
    template<class InputIt, class UnaryFunc>
    constexpr UnaryFunc for_each(InputIt first, InputIt last, UnaryFunc f)
    {
    for (; first != last; ++first)
    f(*first);

    return f;
    }
  • 例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    #include <algorithm>
    #include <iostream>
    #include <vector>

    int main()
    {
    std::vector<int> v{3, -4, 2, -8, 15, 267};

    auto print = [](const int& n) { std::cout << n << ' '; };

    std::cout << "before:\t";
    std::for_each(v.cbegin(), v.cend(), print);
    std::cout << '\n';

    // increment elements in-place
    std::for_each(v.begin(), v.end(), [](int &n) { n++; });

    std::cout << "after:\t";
    std::for_each(v.cbegin(), v.cend(), print);
    std::cout << '\n';

    struct Sum
    {
    void operator()(int n) { sum += n; }
    int sum {0};
    };
    Sum s = std::for_each(v.cbegin(), v.cend(), Sum());
    std::cout << "sum:\t" << s.sum << '\n';
    }
    1
    2
    3
    4
    // 输出
    before: 3 -4 2 -8 15 267
    after: 4 -3 3 -7 16 268
    sum: 281
transform
  • 用法:将一个容器中的内容搬运到另一个容器中
  • first1:开始的迭代器
  • last1:结束的迭代器
  • d_first:目的容器开始的迭代器
  • f:传入的函数
  • 可能的实现:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // 从first1到last1的元素传入unary_op变换后,放到d_first内
    emplate<class InputIt, class OutputIt, class UnaryOp>
    constexpr //< since C++20
    OutputIt transform(InputIt first1, InputIt last1, OutputIt d_first, UnaryOp unary_op)
    {
    for (; first1 != last1; ++d_first, ++first1)
    *d_first = unary_op(*first1);

    return d_first;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 从first1到last1和从first2后的元素传入unary_op(first1,first2)变换后,放到d_first内
    // first2的范围应该小于first1到last1的范围
    template<class InputIt1, class InputIt2,
    class OutputIt, class BinaryOp>
    constexpr //< since C++20
    OutputIt transform(InputIt1 first1, InputIt1 last1, InputIt2 first2, OutputIt d_first, BinaryOp binary_op)
    {
    for (; first1 != last1; ++d_first, ++first1, ++first2)
    *d_first = binary_op(*first1, *first2);

    return d_first;
    }
  • 例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    #include <algorithm>
    #include <cctype>
    #include <iomanip>
    #include <iostream>
    #include <string>
    #include <utility>
    #include <vector>

    void print_ordinals(const std::vector<unsigned>& ordinals)
    {
    std::cout << "ordinals: ";
    for (unsigned ord : ordinals)
    std::cout << std::setw(3) << ord << ' ';
    std::cout << '\n';
    }

    char to_uppercase(unsigned char c)
    {
    return std::toupper(c);
    }

    void to_uppercase_inplace(char& c)
    {
    c = to_uppercase(c);
    }

    void unary_transform_example(std::string& hello, std::string world)
    {
    // 原地转换成大写字母

    std::transform(hello.cbegin(), hello.cend(), hello.begin(), to_uppercase);
    std::cout << "hello = " << std::quoted(hello) << '\n';

    // for_each版本
    std::for_each(world.begin(), world.end(), to_uppercase_inplace);
    std::cout << "world = " << std::quoted(world) << '\n';
    }

    void binary_transform_example(std::vector<unsigned> ordinals)
    {
    // 转化成两倍的值

    print_ordinals(ordinals);

    std::transform(ordinals.cbegin(), ordinals.cend(), ordinals.cbegin(),
    ordinals.begin(), std::plus<>{});

    print_ordinals(ordinals);
    }

    int main()
    {
    std::string hello("hello");
    unary_transform_example(hello, "world");

    std::vector<unsigned> ordinals;
    std::copy(hello.cbegin(), hello.cend(), std::back_inserter(ordinals));
    binary_transform_example(std::move(ordinals));
    }
    1
    2
    3
    4
    5
    // 输出
    hello = "HELLO"
    world = "WORLD"
    ordinals: 72 69 76 76 79
    ordinals: 144 138 152 152 158
find,find_if,find_if_not
  • 用法:查找指定元素,找到返回指定元素的迭代器,找不到返回结束迭代器end()
  • first:开始迭代器
  • last:结束迭代器
  • value:查找的元素 | p/q:传入的判断函数
  • 可能的实现:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // find
    template<class InputIt, class T = typename std::iterator_traits<InputIt>::value_type>
    constexpr InputIt find(InputIt first, InputIt last, const T& value)
    {
    for (; first != last; ++first)
    if (*first == value)
    return first;

    return last;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // find_if
    template<class InputIt, class UnaryPred>
    constexpr InputIt find_if(InputIt first, InputIt last, UnaryPred p)
    {
    for (; first != last; ++first)
    if (p(*first))
    return first;

    return last;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // find_if_not
    template<class InputIt, class UnaryPred>
    constexpr InputIt find_if_not(InputIt first, InputIt last, UnaryPred q)
    {
    for (; first != last; ++first)
    if (!q(*first))
    return first;

    return last;
    }
  • 例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    #include <algorithm>
    #include <array>
    #include <cassert>
    #include <complex>
    #include <iostream>
    #include <vector>

    int main()
    {
    const auto v = {1, 2, 3, 4};

    for (const int n : {3, 5})
    (std::find(v.begin(), v.end(), n) == std::end(v))
    ? std::cout << "v does not contain " << n << '\n'
    : std::cout << "v contains " << n << '\n';

    auto is_even = [](int i) { return i % 2 == 0; };

    for (const auto& w : {std::array{3, 1, 4}, {1, 3, 5}})
    if (auto it = std::find_if(begin(w), end(w), is_even); it != std::end(w))
    std::cout << "w contains an even number " << *it << '\n';
    else
    std::cout << "w does not contain even numbers\n";

    std::vector<std::complex<double>> nums{{4, 2}};
    #ifdef __cpp_lib_default_template_type_for_algorithm_values
    // T gets deduced making list-initialization possible
    const auto it = std::find(nums.begin(), nums.end(), {4, 2});
    #else
    const auto it = std::find(nums.begin(), nums.end(), std::complex<double>{4, 2});
    #endif
    assert(it == nums.begin());
    }
    1
    2
    3
    4
    5
    // 输出
    v contains 3
    v does not contain 5
    w contains an even number 4
    w does not contain even numbers
adjacent_find
  • 用法:查找相邻的重复元素,返回相邻元素的第一个位置的迭代器
  • first:开始的迭代器
  • last:结束的迭代器
  • p:传入的自定义判断函数
  • 可能的实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 默认判断相等
    template<class ForwardIt>
    ForwardIt adjacent_find(ForwardIt first, ForwardIt last)
    {
    if (first == last)
    return last;

    ForwardIt next = first;
    ++next;

    for (; next != last; ++next, ++first)
    if (*first == *next)
    return first;

    return last;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 自定义判断相等
    template<class ForwardIt, class BinaryPred>
    ForwardIt adjacent_find(ForwardIt first, ForwardIt last, BinaryPred p)
    {
    if (first == last)
    return last;

    ForwardIt next = first;
    ++next;

    for (; next != last; ++next, ++first)
    if (p(*first, *next))
    return first;

    return last;
    }
  • 例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #include <algorithm>
    #include <functional>
    #include <iostream>
    #include <vector>

    int main()
    {
    std::vector<int> v1{0, 1, 2, 3, 40, 40, 41, 41, 5};

    auto i1 = std::adjacent_find(v1.begin(), v1.end());

    if (i1 == v1.end())
    std::cout << "No matching adjacent elements\n";
    else
    std::cout << "The first adjacent pair of equal elements is at "
    << std::distance(v1.begin(), i1) << ", *i1 = "
    << *i1 << '\n';

    auto i2 = std::adjacent_find(v1.begin(), v1.end(), std::greater<int>());
    if (i2 == v1.end())
    std::cout << "The entire vector is sorted in ascending order\n";
    else
    std::cout << "The last element in the non-decreasing subsequence is at "
    << std::distance(v1.begin(), i2) << ", *i2 = " << *i2 << '\n';
    }
    1
    2
    3
    //输出
    The first adjacent pair of equal elements is at 4, *i1 = 40
    The last element in the non-decreasing subsequence is at 7, *i2 = 41
  • 用法:二分查找
  • first:开始的迭代器
  • last:结束的迭代器
  • value:查找的值
  • comp:传入的自定义判断函数
  • 可能的实现:
    1
    2
    3
    4
    5
    template<class ForwardIt, class T = typename std::iterator_traits<ForwardIt>::value_type>
    bool binary_search(ForwardIt first, ForwardIt last, const T& value)
    {
    return std::binary_search(first, last, value, std::less{});
    }
    1
    2
    3
    4
    5
    6
    7
    template<class ForwardIt, class T = typename std::iterator_traits<ForwardIt>::value_type,
    class Compare>
    bool binary_search(ForwardIt first, ForwardIt last, const T& value, Compare comp)
    {
    first = std::lower_bound(first, last, value, comp);
    return (!(first == last) and !(comp(value, *first)));
    }
  • 例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    #include <algorithm>
    #include <cassert>
    #include <complex>
    #include <iostream>
    #include <vector>

    int main()
    {
    const auto haystack = {1, 3, 4, 5, 9};

    for (const auto needle : {1, 2, 3})
    {
    std::cout << "Searching for " << needle << '\n';
    if (std::binary_search(haystack.begin(), haystack.end(), needle))
    std::cout << "Found " << needle << '\n';
    else
    std::cout << "No dice!\n";
    }

    using CD = std::complex<double>;
    std::vector<CD> nums{{1, 1}, {2, 3}, {4, 2}, {4, 3}};
    auto cmpz = [](CD x, CD y){ return abs(x) < abs(y); };
    #ifdef __cpp_lib_default_template_type_for_algorithm_values
    assert(std::binary_search(nums.cbegin(), nums.cend(), {4, 2}, cmpz));
    #else
    assert(std::binary_search(nums.cbegin(), nums.cend(), CD{4, 2}, cmpz));
    #endif
    }
    1
    2
    3
    4
    5
    6
    7
    //输出
    Searching for 1
    Found 1
    Searching for 2
    no dice!
    Searching for 3
    Found 3
count,count_if
  • 用法:统计一个区间中元素出现的次数
  • first:开始的迭代器
  • last:结束的迭代器
  • value:查找的值
  • p:传入的判断函数
  • 可能的实现:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template<class InputIt, class T = typename std::iterator_traits<InputIt>::value_type>
    typename std::iterator_traits<InputIt>::difference_type
    count(InputIt first, InputIt last, const T& value)
    {
    typename std::iterator_traits<InputIt>::difference_type ret = 0;
    for (; first != last; ++first)
    if (*first == value)
    ++ret;
    return ret;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template<class InputIt, class UnaryPred>
    typename std::iterator_traits<InputIt>::difference_type
    count_if(InputIt first, InputIt last, UnaryPred p)
    {
    typename std::iterator_traits<InputIt>::difference_type ret = 0;
    for (; first != last; ++first)
    if (p(*first))
    ++ret;
    return ret;
    }
  • 例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    #include <algorithm>
    #include <array>
    #include <cassert>
    #include <complex>
    #include <iostream>
    #include <iterator>

    int main()
    {
    constexpr std::array v{1, 2, 3, 4, 4, 3, 7, 8, 9, 10};
    std::cout << "v: ";
    std::copy(v.cbegin(), v.cend(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';

    // 确定有多少整数匹配
    for (const int target : {3, 4, 5})
    {
    const int num_items = std::count(v.cbegin(), v.cend(), target);
    std::cout << "number: " << target << ", count: " << num_items << '\n';
    }

    // 使用lambda找出能被4整除的数字
    int count_div4 = std::count_if(v.begin(), v.end(), [](int i) { return i % 4 == 0; });
    std::cout << "numbers divisible by four: " << count_div4 << '\n';

    // 一个复杂度为O(n)的计算容器元素距离的函数
    auto distance = [](auto first, auto last)
    {
    return std::count_if(first, last, [](auto) { return true; });
    };
    static_assert(distance(v.begin(), v.end()) == 10);

    std::array<std::complex<double>, 3> nums{{{4, 2}, {1, 3}, {4, 2}}};
    #ifdef __cpp_lib_default_template_type_for_algorithm_values
    // T gets deduced making list-initialization possible
    auto c = std::count(nums.cbegin(), nums.cend(), {4, 2});
    #else
    auto c = std::count(nums.cbegin(), nums.cend(), std::complex<double>{4, 2});
    #endif
    assert(c == 2);
    }
    1
    2
    3
    4
    5
    6
    //输出
    v: 1 2 3 4 4 3 7 8 9 10
    number: 3, count: 2
    number: 4, count: 2
    number: 5, count: 0
    numbers divisible by four: 3
  • 用法:给出两个范围,返回一个迭代器,查找成功指向第一个范围内第一次出现子序列,查找失败指向last1。
  • first:开始的迭代器
  • last:结束的迭代器
  • p:传入的函数
  • 可能的实现:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    template<class ForwardIt1, class ForwardIt2>
    constexpr //< since C++20
    ForwardIt1 search(ForwardIt1 first, ForwardIt1 last,
    ForwardIt2 s_first, ForwardIt2 s_last)
    {
    while (true)
    {
    ForwardIt1 it = first;
    for (ForwardIt2 s_it = s_first; ; ++it, ++s_it)
    {
    if (s_it == s_last)
    return first;
    if (it == last)
    return last;
    if (!(*it == *s_it))
    break;
    }
    ++first;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    template<class ForwardIt1, class ForwardIt2, class BinaryPred>
    constexpr //< since C++20
    ForwardIt1 search(ForwardIt1 first, ForwardIt1 last,
    ForwardIt2 s_first, ForwardIt2 s_last, BinaryPred p)
    {
    while (true)
    {
    ForwardIt1 it = first;
    for (ForwardIt2 s_it = s_first; ; ++it, ++s_it)
    {
    if (s_it == s_last)
    return first;
    if (it == last)
    return last;
    if (!p(*it, *s_it))
    break;
    }
    ++first;
    }
    }
  • 例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    #include <algorithm>
    #include <cassert>
    #include <functional>
    #include <iomanip>
    #include <iostream>
    #include <iterator>
    #include <string_view>
    #include <vector>

    using namespace std::literals;

    bool contains(const auto& cont, std::string_view s)
    {
    // str.find() (or str.contains(), since C++23) can be used as well
    return std::search(cont.begin(), cont.end(), s.begin(), s.end()) != cont.end();
    }

    int main()
    {
    const auto str{"why waste time learning, when ignorance is instantaneous?"sv};
    assert(contains(str, "learning"));
    assert(not contains(str, "lemming"));

    const std::vector vec(str.begin(), str.end());
    assert(contains(vec, "learning"));
    assert(not contains(vec, "leaning"));

    // The C++17 overload with searchers demo:
    constexpr auto quote
    {
    "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed "
    "do eiusmod tempor incididunt ut labore et dolore magna aliqua"sv
    };

    for (const auto word : {"pisci"sv, "Pisci"sv})
    {
    std::cout << "The string " << std::quoted(word) << ' ';
    const std::boyer_moore_searcher searcher(word.begin(), word.end());
    const auto it = std::search(quote.begin(), quote.end(), searcher);
    if (it == quote.end())
    std::cout << "not found\n";
    else
    std::cout << "found at offset " << std::distance(quote.begin(), it) << '\n';
    }
    }
    1
    2
    3
    // 输出
    The string "pisci" found at offset 43
    The string "Pisci" not found

排序算法

sort
  • 用法:快速排序
  • first:开始的迭代器
  • last:结束的迭代器
  • comp:传入的比较函数
  • 例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    #include <algorithm>
    #include <array>
    #include <functional>
    #include <iostream>
    #include <string_view>

    int main()
    {
    std::array<int, 10> s{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};

    auto print = [&s](std::string_view const rem)
    {
    for (auto a : s)
    std::cout << a << ' ';
    std::cout << ": " << rem << '\n';
    };

    std::sort(s.begin(), s.end());
    print("sorted with the default operator<");

    std::sort(s.begin(), s.end(), std::greater<int>());
    print("sorted with the standard library compare function object");

    struct
    {
    bool operator()(int a, int b) const { return a < b; }
    }
    customLess;

    std::sort(s.begin(), s.end(), customLess);
    print("sorted with a custom function object");

    std::sort(s.begin(), s.end(), [](int a, int b)
    {
    return a > b;
    });
    print("sorted with a lambda expression");
    }
    1
    2
    3
    4
    5
    //输出
    0 1 2 3 4 5 6 7 8 9 : sorted with the default operator<
    9 8 7 6 5 4 3 2 1 0 : sorted with the standard library compare function object
    0 1 2 3 4 5 6 7 8 9 : sorted with a custom function object
    9 8 7 6 5 4 3 2 1 0 : sorted with a lambda expression
random_shuffle
  • 用法:随机打乱
  • first:开始的迭代器
  • last:结束的迭代器
  • RandomFunc:传入的随机函数
  • 可能的实现:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // 默认实现
    template<class RandomIt>
    void random_shuffle(RandomIt first, RandomIt last)
    {
    typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;

    for (diff_t i = last - first - 1; i > 0; --i)
    {
    using std::swap;
    swap(first[i], first[std::rand() % (i + 1)]);
    // rand() % (i + 1) is not actually correct, because the generated number is
    // not uniformly distributed for most values of i. The correct code would be
    // a variation of the C++11 std::uniform_int_distribution implementation.
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 自定义随机函数
    template<class RandomIt, class RandomFunc>
    void random_shuffle(RandomIt first, RandomIt last, RandomFunc&& r)
    {
    typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;

    for (diff_t i = last - first - 1; i > 0; --i)
    {
    using std::swap;
    swap(first[i], first[r(i + 1)]);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // 不知道
    template<class RandomIt, class URBG>
    void shuffle(RandomIt first, RandomIt last, URBG&& g)
    {
    typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
    typedef std::uniform_int_distribution<diff_t> distr_t;
    typedef typename distr_t::param_type param_t;

    distr_t D;
    for (diff_t i = last - first - 1; i > 0; --i)
    {
    using std::swap;
    swap(first[i], first[D(g, param_t(0, i))]);
    }
    }
  • 例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #include <algorithm>
    #include <iostream>
    #include <iterator>
    #include <random>
    #include <vector>

    int main()
    {
    std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    std::random_device rd;
    std::mt19937 g(rd());

    std::shuffle(v.begin(), v.end(), g);

    std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';
    }
    1
    2
    //输出
    8 6 10 4 2 3 7 1 9 5
merge
  • 用法:容器合并
  • first1:容器1的开始迭代器
  • last1:容器1的结束迭代器
  • first2:容器2的开始迭代器
  • last2:容器2的结束迭代器
  • d_first:目标容器的起始迭代器
  • 可能的实现:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // 默认小的放后面
    template<class InputIt1, class InputIt2, class OutputIt>
    OutputIt merge(InputIt1 first1, InputIt1 last1,
    InputIt2 first2, InputIt2 last2,
    OutputIt d_first)
    {
    for (; first1 != last1; ++d_first)
    {
    if (first2 == last2)
    return std::copy(first1, last1, d_first);

    if (*first2 < *first1)
    {
    *d_first = *first2;
    ++first2;
    }
    else
    {
    *d_first = *first1;
    ++first1;
    }
    }
    return std::copy(first2, last2, d_first);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // 自定义放的顺序
    template<class InputIt1, class InputIt2,
    class OutputIt, class Compare>
    OutputIt merge(InputIt1 first1, InputIt1 last1,
    InputIt2 first2, InputIt2 last2,
    OutputIt d_first, Compare comp)
    {
    for (; first1 != last1; ++d_first)
    {
    if (first2 == last2)
    return std::copy(first1, last1, d_first);

    if (comp(*first2, *first1))
    {
    *d_first = *first2;
    ++first2;
    }
    else
    {
    *d_first = *first1;
    ++first1;
    }
    }
    return std::copy(first2, last2, d_first);
    }
  • 例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    #include <algorithm>
    #include <functional>
    #include <iostream>
    #include <iterator>
    #include <random>
    #include <vector>

    auto print = [](const auto rem, const auto& v)
    {
    std::cout << rem;
    std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';
    };

    int main()
    {
    // 随机数填充
    std::random_device rd;
    std::mt19937 mt(rd());
    std::uniform_int_distribution<> dis(0, 9);

    std::vector<int> v1(10), v2(10);
    std::generate(v1.begin(), v1.end(), std::bind(dis, std::ref(mt)));
    std::generate(v2.begin(), v2.end(), std::bind(dis, std::ref(mt)));

    print("Originally:\nv1: ", v1);
    print("v2: ", v2);

    std::sort(v1.begin(), v1.end());
    std::sort(v2.begin(), v2.end());

    print("After sorting:\nv1: ", v1);
    print("v2: ", v2);

    // merge
    std::vector<int> dst;
    std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(dst));

    print("After merging:\ndst: ", dst);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //输出
    Originally:
    v1: 2 6 5 7 4 2 2 6 7 0
    v2: 8 3 2 5 0 1 9 6 5 0
    After sorting:
    v1: 0 2 2 2 4 5 6 6 7 7
    v2: 0 0 1 2 3 5 5 6 8 9
    After merging:
    dst: 0 0 0 1 2 2 2 2 3 4 5 5 5 6 6 6 7 7 8 9
reverse
  • 用法:将容器内的元素进行一个反转
  • first:开始的迭代器
  • last:结束的迭代器
  • 可能的实现:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    template<class BidirIt>
    constexpr // since C++20
    void reverse(BidirIt first, BidirIt last)
    {
    using iter_cat = typename std::iterator_traits<BidirIt>::iterator_category;

    // Tag dispatch, e.g. calling reverse_impl(first, last, iter_cat()),
    // can be used in C++14 and earlier modes.
    if constexpr (std::is_base_of_v<std::random_access_iterator_tag, iter_cat>)
    {
    if (first == last)
    return;

    for (--last; first < last; (void)++first, --last)
    std::iter_swap(first, last);
    }
    else
    while (first != last && first != --last)
    std::iter_swap(first++, last);
    }
  • 例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #include <algorithm>
    #include <iostream>
    #include <iterator>
    #include <vector>

    void println(auto rem, auto const& v)
    {
    for (std::cout << rem; auto e : v)
    std::cout << e << ' ';
    std::cout << '\n';
    }

    int main()
    {
    std::vector<int> v {1, 2, 3};
    std::reverse(v.begin(), v.end());
    println("after reverse, v = ", v);

    int a[] = {4, 5, 6, 7};
    std::reverse(std::begin(a), std::end(a));
    println("after reverse, a = ", a);
    }
    1
    2
    3
    //输出
    after reverse, v = 3 2 1
    after reverse, a = 7 6 5 4

拷贝和替换算法

copy,copy_if
  • 用法:将容器内的元素拷贝到另一容器中
  • first:开始的迭代器
  • last:结束的迭代器
  • d_first:目的容器的开始迭代器
  • pred:判断函数
  • 可能的实现:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template<class InputIt, class OutputIt>
    OutputIt copy(InputIt first, InputIt last,
    OutputIt d_first)
    {
    for (; first != last; (void)++first, (void)++d_first)
    *d_first = *first;

    return d_first;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    template<class InputIt, class OutputIt>
    OutputIt copy_if(InputIt first, InputIt last,
    OutputIt d_first, UnaryPred pred)
    {
    for (; first != last; ++first)
    if (pred(*first))
    {
    *d_first = *first;
    ++d_first;
    }

    return d_first;
    }
  • 例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    #include <algorithm>
    #include <iostream>
    #include <iterator>
    #include <numeric>
    #include <vector>

    int main()
    {
    std::vector<int> from_vector(10);
    std::iota(from_vector.begin(), from_vector.end(), 0);

    std::vector<int> to_vector;
    std::copy(from_vector.begin(), from_vector.end(),
    std::back_inserter(to_vector));
    // 或者还可以这样做,
    // std::vector<int> to_vector(from_vector.size());
    // std::copy(from_vector.begin(), from_vector.end(), to_vector.begin());
    // 同样地,
    // std::vector<int> to_vector = from_vector;

    std::cout << "to_vector contains: ";

    std::copy(to_vector.begin(), to_vector.end(),
    std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';

    std::cout << "odd numbers in to_vector are: ";

    std::copy_if(to_vector.begin(), to_vector.end(),
    std::ostream_iterator<int>(std::cout, " "),
    [](int x) { return x % 2 != 0; });
    std::cout << '\n';

    std::cout << "to_vector contains these multiples of 3: ";

    to_vector.clear();
    std::copy_if(from_vector.begin(), from_vector.end(),
    std::back_inserter(to_vector),
    [](int x) { return x % 3 == 0; });

    for (const int x : to_vector)
    std::cout << x << ' ';
    std::cout << '\n';
    }
    1
    2
    3
    4
    //输出
    to_vector contains: 0 1 2 3 4 5 6 7 8 9
    odd numbers in to_vector are: 1 3 5 7 9
    to_vector contains these multiples of 3: 0 3 6 9
replace,replace_if
  • 用法:将容器内指定范围内的元素替换成新元素
  • first:开始的迭代器
  • last:结束的迭代器
  • old_value:待替换的值
  • p:判断是否满足替换条件的函数
  • new_value:替换后的值
  • 可能的实现:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template<class ForwardIt,
    class T = typename std::iterator_traits<ForwardIt>::value_type>
    void replace(ForwardIt first, ForwardIt last,
    const T& old_value, const T& new_value)
    {
    for (; first != last; ++first)
    if (*first == old_value)
    *first = new_value;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template<class ForwardIt, class UnaryPred,
    class T = typename std::iterator_traits<ForwardIt>::value_type>
    void replace_if(ForwardIt first, ForwardIt last,
    UnaryPred p, const T& new_value)
    {
    for (; first != last; ++first)
    if (p(*first))
    *first = new_value;
    }
  • 例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    #include <algorithm>
    #include <array>
    #include <complex>
    #include <functional>
    #include <iostream>

    void println(const auto& seq)
    {
    for (const auto& e : seq)
    std::cout << e << ' ';
    std::cout << '\n';
    }

    int main()
    {
    std::array<int, 10> s{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};

    // 将所有的8替换成88
    std::replace(s.begin(), s.end(), 8, 88);
    println(s);

    // 将所有的5替换成55
    std::replace_if(s.begin(), s.end(),
    std::bind(std::less<int>(), std::placeholders::_1, 5), 55);
    println(s);

    std::array<std::complex<double>, 2> nums{{{1, 3}, {1, 3}}};
    #ifdef __cpp_lib_default_template_type_for_algorithm_values
    std::replace(nums.begin(), nums.end(), {1, 3}, {4, 2});
    #else
    std::replace(nums.begin(), nums.end(), std::complex<double>{1, 3},
    std::complex<double>{4, 2});
    #endif
    println(nums);
    }
    1
    2
    3
    4
    //输出
    5 7 4 2 88 6 1 9 0 3
    5 7 55 55 88 6 55 9 55 55
    (4,2), (4,2)
swap
  • 用法:交换元素
  • c1:容器A
  • c2:容器B
  • 可能的实现:
    1
    void swap(Container1 c1,Container c2);
  • 例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    #include <algorithm>
    #include <iostream>

    namespace Ns
    {
    class A
    {
    int id {};

    friend void swap(A& lhs, A& rhs)
    {
    std::cout << "swap(" << lhs << ", " << rhs << ")\n";
    std::swap(lhs.id, rhs.id);
    }

    friend std::ostream& operator<<(std::ostream& os, A const& a)
    {
    return os << "A::id=" << a.id;
    }

    public:
    A(int i) : id {i} {}
    A(A const&) = delete;
    A& operator = (A const&) = delete;
    };
    }

    int main()
    {
    int a = 5, b = 3;
    std::cout << a << ' ' << b << '\n';
    std::swap(a, b);
    std::cout << a << ' ' << b << '\n';

    Ns::A p {6}, q {9};
    std::cout << p << ' ' << q << '\n';
    // std::swap(p, q); // 标准库中没有相关实现
    swap(p, q); // 需要自定义swap函数
    std::cout << p << ' ' << q << '\n';
    }
    1
    2
    3
    4
    5
    6
    //输出
    5 3
    3 5
    A::id=6 A::id=9
    swap(A::id=6, A::id=9)
    A::id=9 A::id=6

算数生成算法

所属的头文件并不是algorithm,而是我们开头提到过的 numeric

accumulate
  • 用法:计算一个指定区间内的总和
  • first:容器A
  • last:容器B
  • init:初始值
  • op:计算函数
  • 可能的实现:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template<class InputIt, class T>
    constexpr // since C++20
    T accumulate(InputIt first, InputIt last, T init)
    {
    for (; first != last; ++first)
    init = std::move(init) + *first; // std::move since C++20

    return init;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template<class InputIt, class T, class BinaryOperation>
    constexpr // since C++20
    T accumulate(InputIt first, InputIt last, T init, BinaryOperation op)
    {
    for (; first != last; ++first)
    init = op(std::move(init), *first); // std::move since C++20

    return init;
    }
  • 例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    #include <functional>
    #include <iostream>
    #include <numeric>
    #include <string>
    #include <vector>

    int main()
    {
    std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    int sum = std::accumulate(v.begin(), v.end(), 0);
    int product = std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>());

    // 从左开始,以"-"链接起来
    auto dash_fold = [](std::string a, int b)
    {
    return std::move(a) + '-' + std::to_string(b);
    };

    std::string s = std::accumulate(std::next(v.begin()), v.end(),
    std::to_string(v[0]), // 从第一个开始
    dash_fold);

    // 从右开始,使用反向迭代器
    std::string rs = std::accumulate(std::next(v.rbegin()), v.rend(),
    std::to_string(v.back()), // 从最后一个开始
    dash_fold);

    std::cout << "sum: " << sum << '\n'
    << "product: " << product << '\n'
    << "dash-separated string: " << s << '\n'
    << "dash-separated string (right-folded): " << rs << '\n';
    }
    1
    2
    3
    4
    5
    //输出
    sum: 55
    product: 3628800
    dash-separated string: 1-2-3-4-5-6-7-8-9-10
    dash-separated string (right-folded): 10-9-8-7-6-5-4-3-2-1
fill
  • 用法:向容器中填充指定的元素
  • first:开始的迭代器
  • last:结束的迭代器
  • value:填充的值
  • 可能的实现:
    1
    2
    3
    4
    5
    6
    7
    template<class ForwardIt,
    class T = typename std::iterator_traits<ForwardIt>::value_type>
    void fill(ForwardIt first, ForwardIt last, const T& value)
    {
    for (; first != last; ++first)
    *first = value;
    }
  • 例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    #include <algorithm>
    #include <complex>
    #include <iostream>
    #include <vector>

    void println(const auto& seq)
    {
    for (const auto& e : seq)
    std::cout << e << ' ';
    std::cout << '\n';
    }

    int main()
    {
    std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8};
    println(v);

    // 把所有的元素设置成8
    std::fill(v.begin(), v.end(), 8);
    println(v);

    std::vector<std::complex<double>> nums{{1, 3}, {2, 2}, {4, 8}};
    println(nums);
    #ifdef __cpp_lib_default_template_type_for_algorithm_values
    std::fill(nums.begin(), nums.end(), {4, 2});
    #else
    std::fill(nums.begin(), nums.end(), std::complex<double>{4, 2});
    #endif
    println(nums);
    }
    1
    2
    3
    4
    5
    //输出
    0 1 2 3 4 5 6 7 8
    8 8 8 8 8 8 8 8 8
    (1,3) (2,2) (4,8)
    (4,2) (4,2) (4,2)

集合算法

set_intersection,set_union,set_difference
  • 用法:求两个容器中元素的交集,并集,差集
  • first1:容器A开始迭代器
  • last1:容器A结束迭代器
  • first2:容器B开始迭代器
  • last2:容器B结束迭代器
  • d_first:目标容器迭代器
  • comp:比较的函数
  • 可能的实现:

set_intersection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template<class InputIt1, class InputIt2, class OutputIt>
OutputIt set_intersection(InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2, OutputIt d_first)
{
while (first1 != last1 && first2 != last2)
{
if (*first1 < *first2)
++first1;
else
{
if (!(*first2 < *first1))
*d_first++ = *first1++; // *first1 and *first2 are equivalent.
++first2;
}
}
return d_first;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template<class InputIt1, class InputIt2, class OutputIt, class Compare>
OutputIt set_intersection(InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2, OutputIt d_first, Compare comp)
{
while (first1 != last1 && first2 != last2)
{
if (comp(*first1, *first2))
++first1;
else
{
if (!comp(*first2, *first1))
*d_first++ = *first1++; // *first1 and *first2 are equivalent.
++first2;
}
}
return d_first;
}

set_union

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
template<class InputIt1, class InputIt2, class OutputIt>
OutputIt set_union(InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2, OutputIt d_first)
{
for (; first1 != last1; ++d_first)
{
if (first2 == last2)
return std::copy(first1, last1, d_first);

if (*first2 < *first1)
*d_first = *first2++;
else
{
*d_first = *first1;
if (!(*first1 < *first2))
++first2;
++first1;
}
}
return std::copy(first2, last2, d_first);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
template<class InputIt1, class InputIt2, class OutputIt, class Compare>
OutputIt set_union(InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2, OutputIt d_first, Compare comp)
{
for (; first1 != last1; ++d_first)
{
if (first2 == last2)
// Finished range 2, include the rest of range 1:
return std::copy(first1, last1, d_first);

if (comp(*first2, *first1))
*d_first = *first2++;
else
{
*d_first = *first1;
if (!comp(*first1, *first2)) // Equivalent => don't need to include *first2.
++first2;
++first1;
}
}
// Finished range 1, include the rest of range 2:
return std::copy(first2, last2, d_first);
}

set_difference

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template<class InputIt1, class InputIt2, class OutputIt>
OutputIt set_difference(InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2, OutputIt d_first)
{
while (first1 != last1)
{
if (first2 == last2)
return std::copy(first1, last1, d_first);

if (*first1 < *first2)
*d_first++ = *first1++;
else
{
if (! (*first2 < *first1))
++first1;
++first2;
}
}
return d_first;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template<class InputIt1, class InputIt2, class OutputIt, class Compare>
OutputIt set_difference(InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2, OutputIt d_first, Compare comp)
{
while (first1 != last1)
{
if (first2 == last2)
return std::copy(first1, last1, d_first);

if (comp(*first1, *first2))
*d_first++ = *first1++;
else
{
if (!comp(*first2, *first1))
++first1;
++first2;
}
}
return d_first;
}
  • 例子:

set_intersection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

int main()
{
std::vector<int> v1{7, 2, 3, 4, 5, 6, 7, 8};
std::vector<int> v2{5, 7, 9, 7};
std::sort(v1.begin(), v1.end());
std::sort(v2.begin(), v2.end());

std::vector<int> v_intersection;
std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(),
std::back_inserter(v_intersection));

for (int n : v_intersection)
std::cout << n << ' ';
std::cout << '\n';
}
1
2
//输出
5 7 7

set_union

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

void println(const std::vector<int>& v)
{
for (int i : v)
std::cout << i << ' ';
std::cout << '\n';
}

int main()
{
std::vector<int> v1, v2, dest;

v1 = {1, 2, 3, 4, 5};
v2 = {3, 4, 5, 6, 7};

std::set_union(v1.cbegin(), v1.cend(),
v2.cbegin(), v2.cend(),
std::back_inserter(dest));
println(dest);

dest.clear();

v1 = {1, 2, 3, 4, 5, 5, 5};
v2 = {3, 4, 5, 6, 7};

std::set_union(v1.cbegin(), v1.cend(),
v2.cbegin(), v2.cend(),
std::back_inserter(dest));
println(dest);
}
1
2
3
//输出
1 2 3 4 5 6 7
1 2 3 4 5 5 5 6 7

set_intersection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

template<typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v)
{
os << '{';
for (auto n{v.size()}; const auto& e : v)
os << e << (--n ? ", " : "");
return os << '}';
}

struct Order
{
int order_id{};

friend std::ostream& operator<<(std::ostream& os, const Order& ord)
{
return os << ord.order_id;
}
};

int main()
{
const std::vector<int> v1{1, 2, 5, 5, 5, 9};
const std::vector<int> v2{2, 5, 7};
std::vector<int> diff;

std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(),
std::inserter(diff, diff.begin()));

std::cout << v1 << " ∖ " << v2 << " == " << diff << "\n\n";

std::vector<Order> old_orders{{1}, {2}, {5}, {9}};
std::vector<Order> new_orders{{2}, {5}, {7}};
std::vector<Order> cut_orders;

std::set_difference(old_orders.begin(), old_orders.end(),
new_orders.begin(), new_orders.end(),
std::back_inserter(cut_orders),
[](auto& a, auto& b) { return a.order_id < b.order_id; });

std::cout << "old orders: " << old_orders << '\n'
<< "new orders: " << new_orders << '\n'
<< "cut orders: " << cut_orders << '\n';
}
1
2
3
4
5
6
//输出
{1, 2, 5, 5, 5, 9} ∖ {2, 5, 7} == {1, 5, 5, 9}

old orders: {1, 2, 5, 9}
new orders: {2, 5, 7}
cut orders: {1, 9}