C++ Annotations Version 12.5.0 学习(4)

maxmin

在这里插入图片描述

maxmin 是 C++ 标准库中的两个算法,用于返回两个元素中的最大值或最小值。它们有多个重载版本,可以通过默认比较操作或自定义比较函数来进行比较。

头文件:

#include <algorithm>

函数原型:

Type const &max(Type const &one, Type const &two);

Type const &max(Type const &one, Type const &two, Comparator comp);

Type const &min(Type const &one, Type const &two);

Type const &min(Type const &one, Type const &two, Comparator comp);

描述:

  • 第一个原型:返回两个元素 onetwo 中的较大者。使用数据类型的 operator> 来确定哪个元素更大。

  • 第二个原型:返回 one,如果 comp(one, two) 返回 true,否则返回 two。这里 comp 是一个二元谓词,用于决定两个元素的比较。

  • 第三个原型:与第一个原型类似,但返回的是两个元素中的较小者,使用 operator< 来比较。

  • 第四个原型:与第二个原型类似,但返回的是两个元素中的较小者,使用 comp 进行比较。

示例:

#include <algorithm>
#include <iostream>
#include <string>
#include <cstring>

using namespace std;

bool caseString(string const &first, string const &second)
{
    return strcasecmp(first.c_str(), second.c_str()) <= 0;
}

string const &call(bool first, string const &lhs, string const &rhs)
{
    return first ? max(lhs, rhs) : min(lhs, rhs);
}

string const &call(bool first, string const &lhs, string const &rhs, bool (*cmp)(string const &, string const &))
{
    return first ? max(lhs, rhs, cmp) : min(lhs, rhs, cmp);
}

int main(int argc, char **argv) // no args: use max, else min
{
    bool fun = argc == 1;
    char const *where = fun ? "last\n" : "first\n";
    cout << "Word '" << call(fun, "first", "second") <<
        "' is lexicographically " << where <<
        "Word '" << call(fun, "first", "SECOND") <<
        "' is lexicographically " << where <<
        "Word '" << call(fun, "first", "SECOND", caseString) <<
        "' is lexicographically " << where;
}

输出结果:

  • 无参数调用时
Word 'second' is lexicographically last
Word 'first' is lexicographically last
Word 'SECOND' is lexicographically last
  • 有参数调用时
Word 'first' is lexicographically first
Word 'SECOND' is lexicographically first
Word 'first' is lexicographically first

总结:

  • maxmin 用于返回两个元素中的最大值或最小值。
  • 可以使用默认比较操作(operator>operator<)或自定义的比较函数来确定值的顺序。
  • 示例中演示了如何使用 maxmin 以及自定义的比较函数来比较字符串。

max_element / min_element / minmax_element

在这里插入图片描述

max_elementmin_element 用于找到给定范围内的最大元素和最小元素,而 minmax_element 同时找到最小和最大元素。

头文件:

#include <algorithm>

函数原型:

// 查找最大元素
ForwardIterator max_element([ExecPol,] ForwardIterator first, ForwardIterator last);
ForwardIterator max_element([ExecPol,] ForwardIterator first, ForwardIterator last, BinaryPredicate pred);

// 查找最小元素
ForwardIterator min_element([ExecPol,] ForwardIterator first, ForwardIterator last);
ForwardIterator min_element([ExecPol,] ForwardIterator first, ForwardIterator last, BinaryPredicate pred);

// 查找最小和最大元素
std::pair<ForwardIterator, ForwardIterator> minmax_element([ExecPol,] ForwardIterator first, ForwardIterator last);
std::pair<ForwardIterator, ForwardIterator> minmax_element([ExecPol,] ForwardIterator first, ForwardIterator last, BinaryPredicate pred);

描述:

  • max_element:

    • 第一个原型:返回指向最大元素的迭代器。使用 operator< 来比较元素。
    • 第二个原型:使用自定义的二元谓词 pred 进行比较,返回满足 pred 返回值为 true 的元素。
  • min_element:

    • 第一个原型:返回指向最小元素的迭代器。使用 operator< 来比较元素。
    • 第二个原型:使用自定义的二元谓词 pred 进行比较,返回满足 pred 返回值为 true 的元素。
  • minmax_element:

    • 第一个原型:返回一个 std::pair,包含最小元素和最大元素的迭代器。使用 operator< 来比较元素。
    • 第二个原型:使用自定义的二元谓词 pred 进行比较,返回最小和最大元素的迭代器对。

示例:

#include <algorithm>
#include <iostream>
#include <cstdlib>

using namespace std;

bool absCompare(int first, int second)
{
    return abs(first) < abs(second);
}

int* maxMin(bool high, int* begin, int* end)
{
    return high ? max_element(begin, end) : min_element(begin, end);
}

int* maxMin(bool high, int* begin, int* end, bool (*comp)(int, int))
{
    return high ? max_element(begin, end, comp) : min_element(begin, end, comp);
}

int main(int argc, char **argv)
{
    bool max = argc == 1;
    char const* type = max ? "max" : "min";
    int ia[] = {-4, 7, -2, 10, -12};

    cout << "The " << type << " int value is " <<
        *maxMin(max, ia, ia + 5) << "\n" <<
        "The max. absolute int value is " <<
        *maxMin(max, ia, ia + 5, absCompare) << '\n';
}

输出结果:

当没有命令行参数时:

The max int value is 10
The max. absolute int value is -12

当有命令行参数时:

The min int value is -12
The min. absolute int value is -2

总结:

  • max_elementmin_element 分别用于找到最大和最小元素,支持自定义比较函数。
  • minmax_element 同时返回最小和最大元素,支持自定义比较函数。

merge

在这里插入图片描述

merge 函数用于将两个已排序的范围合并成一个新的已排序范围。

头文件:

#include <algorithm>

函数原型:

// 默认比较操作
OutputIterator merge([ExecPol,] InputIterator1 first1, InputIterator1 last1, 
                     InputIterator2 first2, InputIterator2 last2, 
                     OutputIterator result);

// 自定义比较操作
OutputIterator merge([ExecPol,] InputIterator1 first1, InputIterator1 last1, 
                     InputIterator2 first2, InputIterator2 last2, 
                     OutputIterator result, Compare comp);

描述:

  • 第一个原型:将两个已排序的范围 [first1, last1)[first2, last2) 合并,保持排序顺序。使用数据类型的 operator< 进行比较。结果存储在从 result 开始的范围内,并且返回的迭代器指向合并后的范围的末尾。

  • 第二个原型:将两个已排序的范围 [first1, last1)[first2, last2) 合并,保持排序顺序。使用自定义的比较函数 comp 进行比较。结果存储在从 result 开始的范围内,并且返回的迭代器指向合并后的范围的末尾。比较函数 comp 需要接受两个元素作为参数,并返回布尔值。

示例:

#include <algorithm>
#include <string>
#include <cstring>
#include <iterator>
#include <iostream>

using namespace std;

// 自定义比较函数:不区分大小写的字符串比较
bool caseString(string const &first, string const &second)
{
    return strcasecmp(first.c_str(), second.c_str()) < 0;
}

int main()
{
    // 两个已排序的字符串数组
    string range1[] = { "alpha", "bravo", "foxtrot", "hotel", "zulu" };
    string range2[] = { "delta", "echo", "golf", "romeo" };
    
    // 合并后的结果数组
    string result[5 + 4];
    
    // 使用默认比较操作合并
    copy(result, merge(range1, range1 + 5, range2, range2 + 4, result),
         ostream_iterator<string>{ cout, " " });
    cout << '\n';
    
    // 使用自定义比较函数进行合并(不区分大小写)
    string range3[] = { "ALPHA", "bravo", "foxtrot", "HOTEL", "ZULU" };
    string range4[] = { "delta", "ECHO", "GOLF", "romeo" };
    
    copy(result, merge(range3, range3 + 5, range4, range4 + 4, result, caseString),
         ostream_iterator<string>{ cout, " " });
    cout << '\n';
}

输出结果:

alpha bravo delta echo foxtrot golf hotel romeo zulu
ALPHA bravo delta ECHO foxtrot GOLF HOTEL romeo ZULU

总结:

  • merge 函数可以将两个已排序的范围合并成一个新的已排序范围。
  • 支持默认比较操作和自定义比较操作。自定义比较操作可以实现更复杂的合并逻辑,比如不区分大小写的比较。

minmax

在这里插入图片描述

minmax 函数用于同时找出两个值中的最小值和最大值,并返回这两个值的配对。

头文件:

#include <algorithm>
#include <functional>
#include <iostream>
#include <initializer_list>

函数原型:

// 使用默认比较操作
pair<Type const &, Type const &> minmax(Type const &t1, Type const &t2);

// 使用自定义比较操作
pair<Type const &, Type const &> minmax(Type const &t1, Type const &t2, BinaryPred pred);

// 使用初始化列表,默认比较操作
pair<Type const &, Type const &> minmax(std::initializer_list<Type> values);

// 使用初始化列表,自定义比较操作
pair<Type const &, Type const &> minmax(std::initializer_list<Type> values, BinaryPred pred);

描述:

  • 第一个原型:返回一个 std::pair 对象,其中 first 成员是 t1t2 中较小的值,second 成员是较大的值。比较使用 Typeoperator<

  • 第二个原型:功能与第一个原型相同,但使用自定义的比较函数 pred 进行比较。如果 pred(t1, t2) 返回 true,则 t1 被视为较小值。

  • 第三个原型:功能与第一个原型类似,但适用于初始化列表中的值。返回的 std::pair 对象的 first 成员是初始化列表中的最小值,second 成员是最大值。

  • 第四个原型:功能与第二个原型类似,但适用于初始化列表中的值。使用自定义的比较函数 pred 进行比较。

示例:

#include <algorithm>
#include <functional>
#include <iostream>
#include <initializer_list>
#include <vector>

using namespace std;

int main() {
    // 使用默认比较操作
    auto values = minmax(5, 2);
    cout << values.first << " is smaller than " << values.second << '\n';
    
    // 使用自定义比较操作
    auto values_custom = minmax(5, 2, less<int>{});
    cout << values_custom.first << " is smaller than " << values_custom.second << '\n';
    
    // 使用初始化列表
    auto values_list = minmax({5, 2, 8, 1, 7});
    cout << values_list.first << " is smaller than " << values_list.second << '\n';
    
    // 使用初始化列表和自定义比较操作
    auto values_list_custom = minmax({5, 2, 8, 1, 7}, greater<int>{});
    cout << values_list_custom.first << " is larger than " << values_list_custom.second << '\n';

    return 0;
}

输出:

2 is smaller than 5
2 is smaller than 5
1 is smaller than 8
8 is larger than 1

总结:

  • minmax 函数可以找出两个值中的最小值和最大值,并返回它们的配对。
  • 支持默认比较操作和自定义比较操作。
  • 还可以处理初始化列表,支持对多个值进行最小值和最大值的比较。

mismatch

在这里插入图片描述

mismatch 函数用于比较两个序列中的元素,直到找到第一个不同的元素位置或到达第一个序列的结束。

头文件:

#include <algorithm>
#include <iostream>
#include <string>
#include <utility>

函数原型:

// 使用默认比较操作(operator==)
pair<InputIterator1, InputIterator2> mismatch(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2);

// 使用自定义比较操作
pair<InputIterator1, InputIterator2> mismatch(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, Compare comp);

描述:

  • 第一个原型:比较从 first1first2 开始的两个序列的元素。使用数据类型的 operator== 进行比较。比较在找到第一个不同的元素位置时停止,或者到达 last1。返回一个包含指向第一个不同元素的迭代器的 std::pair 对象。第二个序列可以比第一个序列长。如果第二个序列比第一个序列短,行为未定义。

  • 第二个原型:与第一个原型类似,但使用自定义的比较函数 comp 进行比较。比较在 comp 返回 false 时停止,或者到达 last1。返回一个包含指向第一个不同元素的迭代器的 std::pair 对象。第二个序列可以比第一个序列长。如果第二个序列比第一个序列短,行为未定义。

示例:

#include <algorithm>
#include <cstring>
#include <iostream>
#include <string>
#include <utility>

using namespace std;

bool caseString(string const &first, string const &second) {
    return strcasecmp(first.c_str(), second.c_str()) == 0;
}

int main() {
    string range1[] = { "alpha", "bravo", "foxtrot", "hotel", "zulu" };
    string range2[] = { "alpha", "bravo", "foxtrot", "Hotel", "zulu" };

    // 使用默认比较操作
    pair<string *, string *> pss = mismatch(range1, range1 + 5, range2);
    cout << "The elements " << *pss.first << " and " << *pss.second <<
    " differ at index " << (pss.first - range1) << '\n';

    // 使用自定义比较操作
    if (mismatch(range1, range1 + 5, range2, caseString).first == range1 + 5) {
        cout << "When compared case-insensitively they match\n";
    }

    return 0;
}

输出:

The elements hotel and Hotel differ at index 3
When compared case-insensitively they match

总结:

  • mismatch 函数用于比较两个序列,直到找到第一个不同的元素位置。
  • 可以使用默认的 operator== 比较,也可以使用自定义的比较函数。
  • 如果第二个序列比第一个序列短,行为未定义。

movemove_backward

在这里插入图片描述

这两个算法用于将元素从一个范围移动到另一个范围,其中 move 是前向移动,move_backward 是反向移动。

头文件:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>

函数原型:

// 前向移动
OutputIter move([ExecPol,] InputIter first, InputIter last, OutputIter dest);

// 反向移动
BidirIter move_backward(BidirIter first, BidirIter last, BidirIter lastDest);

描述:

  • 第一个原型 (move):将从迭代器范围 [first, last) 中的所有元素移动到从 dest 开始的范围中,并返回指向 dest 范围最后一个元素之后位置的迭代器。移动操作会将元素从源范围转移到目标范围,但源范围中的元素在移动后仍然有效,但可能已被改变。

  • 第二个原型 (move_backward):将从迭代器范围 [first, last) 中的所有元素以反向顺序移动到从 lastDest 开始的范围中,并返回指向 lastDest 范围开始位置的迭代器。lastDest 不能指向 [first, last) 范围中的元素。移动后,源范围中的元素仍然有效,但可能已被改变。

示例:

#include <algorithm>
#include <string>
#include <iostream>
#include <iterator>

using namespace std;

void show(string const *begin, string const *end) {
    copy(begin, end, ostream_iterator<string>(cout, ", "));
    cout << '\n';
}

int main() {
    string sarr[] = { "alpha", "bravo", "charley", "delta" };
    string dest[4] = { "" };

    auto last = end(sarr);
    auto lastDest = move(sarr, last, dest); // 将所有元素移动到 dest

    cout << "sarr after move:\n";
    show(sarr, last);
    cout << "dest after move:\n";
    show(dest, lastDest);

    move_backward(dest, lastDest, last); // 将元素反向移动到 sarr

    cout << "sarr after move_backward:\n";
    show(sarr, last);
    cout << "dest after move_backward:\n";
    show(dest, lastDest);

    return 0;
}

输出:

sarr after move:
, , , ,
dest after move:
alpha, bravo, charley, delta, 
sarr after move_backward:
alpha, bravo, charley, delta, 
dest after move_backward:
, , , ,

总结:

  • move 函数用于将元素从一个范围移动到另一个范围,并返回目标范围的结束迭代器。
  • move_backward 函数用于将元素以反向顺序移动到另一个范围,并返回目标范围的开始迭代器。
  • 移动后的源范围中的元素仍然有效,但可能已被改变。

next_permutation / prev_permutation

在这里插入图片描述

这两个算法用于生成序列的下一个或上一个排列。

头文件:

#include <algorithm>

函数原型:

// 生成下一个排列
bool next_permutation(BidirectionalIterator first, BidirectionalIterator last);
bool next_permutation(BidirectionalIterator first, BidirectionalIterator last, Comp comp);

// 生成上一个排列
bool prev_permutation(BidirectionalIterator first, BidirectionalIterator last);
bool prev_permutation(BidirectionalIterator first, BidirectionalIterator last, Comp comp);

描述:

  • 第一个原型 (next_permutation):生成给定范围 [first, last) 中元素的下一个排列。对于序列 1, 2, 3,调用 next_permutation 后,元素的排列顺序为:

    • 1 2 3
    • 1 3 2
    • 2 1 3
    • 2 3 1
    • 3 1 2
    • 3 2 1
      这个算法会将序列重新排序,生成下一个更大的排列。如果已经是最后一个排列,则返回 false,并将序列排序成第一个排列。如果重新排序成功,则返回 true
  • 第二个原型 (next_permutationcomp):类似于第一个原型,但使用 comp 作为比较函数来决定元素的排列顺序。comp 是一个二元谓词(返回 truefalse 的函数)。

  • 第三个和第四个原型 (prev_permutation):这些函数的行为与 next_permutation 相同,但生成的是上一个排列而不是下一个排列。

示例:

#include <algorithm>
#include <iterator>
#include <iostream>
#include <string>
#include <cstring>

using namespace std;

bool caseString(string const &first, string const &second) {
    return strcasecmp(first.c_str(), second.c_str()) < 0;
}

int main() {
    string saints[] = { "Oh", "when", "the", "saints" };

    cout << "All permutations of 'Oh when the saints':\nSequences:\n";
    do {
        copy(saints, saints + 4, ostream_iterator<string>{ cout, " " });
        cout << '\n';
    } while (next_permutation(saints, saints + 4, caseString));

    cout << "After first sorting the sequence:\n";
    sort(saints, saints + 4, caseString);

    cout << "Sequences:\n";
    do {
        copy(saints, saints + 4, ostream_iterator<string>{ cout, " " });
        cout << '\n';
    } while (next_permutation(saints, saints + 4, caseString));

    return 0;
}

输出(部分):

All permutations of 'Oh when the saints':
Sequences:
Oh when the saints
Oh when saints the
Oh saints the when
Oh saints when the
Oh the saints when
Oh the when saints
...

After first sorting the sequence:
Sequences:
Oh saints the when
Oh saints when the
Oh the saints when
Oh the when saints
...

总结:

  • next_permutation 用于生成当前序列的下一个排列,并返回 truefalse,表示是否成功生成了下一个排列。
  • prev_permutation 用于生成当前序列的上一个排列,也返回 truefalse
  • 两者均可以使用自定义的比较函数 comp 来确定元素的排列顺序。

nth_element

在这里插入图片描述

头文件:

#include <algorithm>

函数原型:

// 只使用默认比较函数
void nth_element([ExecPol,] RandomAccessIterator first,
                 RandomAccessIterator nth, RandomAccessIterator last);

// 使用自定义比较函数
void nth_element([ExecPol,] RandomAccessIterator first,
                 RandomAccessIterator nth, RandomAccessIterator last,
                 Compare comp);

描述:

  • 第一个原型:在范围 [first, last) 中,将元素相对于 nth 指向的元素进行排序,使得 [first, nth) 中的所有元素都小于 nth 指向的元素,而 [nth + 1, last) 中的所有元素都大于 nth 指向的元素。nth 指向的元素最终处于排序后的中间位置,但 [first, nth)[nth + 1, last) 中的元素不会被进一步排序。比较使用 operator<

  • 第二个原型:与第一个原型类似,但使用 comp 作为比较函数来进行元素比较。comp 是一个二元谓词(返回 truefalse 的函数)。

示例:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <functional>

using namespace std;

int main() {
    int ia[] = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
    
    nth_element(ia, ia + 3, ia + 10);
    cout << "sorting with respect to " << ia[3] << '\n';
    copy(ia, ia + 10, ostream_iterator<int>(cout, " "));
    cout << '\n';

    nth_element(ia, ia + 5, ia + 10, greater<int>());
    cout << "sorting with respect to " << ia[5] << '\n';
    copy(ia, ia + 10, ostream_iterator<int>(cout, " "));
    cout << '\n';

    return 0;
}

输出:

sorting with respect to 4
1 2 3 4 9 7 5 6 8 10

sorting with respect to 5
10 8 7 9 6 5 3 4 2 1

总结:

  • nth_element 函数用于对范围 [first, last) 中的元素进行部分排序,使得 nth 指向的元素在最终排列中处于正确的位置,所有小于 nth 指向的元素都在其前面,所有大于 nth 指向的元素都在其后面。
  • 使用默认比较函数时,元素相对于 nth 指向的元素是以 operator< 为基准的;使用自定义比较函数时,则按照 comp 函数的定义进行排序。

partial_sortpartial_sort_copy

在这里插入图片描述

头文件:

#include <algorithm>

函数原型:

  • partial_sort:

    void partial_sort([ExecPol,] RandomAccessIterator begin,
                       RandomAccessIterator middle, RandomAccessIterator end);
    
    void partial_sort([ExecPol,] RandomAccessIterator begin,
                       RandomAccessIterator middle, RandomAccessIterator end,
                       BinaryPredicate pred);
    
  • partial_sort_copy:

    void partial_sort_copy([ExecPol,] InputIterator begin, InputIterator end,
                           RandomAccessIterator dest_begin, RandomAccessIterator dest_end);
    
    void partial_sort_copy([ExecPol,] InputIterator begin, InputIterator end,
                           RandomAccessIterator dest_begin, RandomAccessIterator dest_end,
                           BinaryPredicate pred);
    

描述:

  • partial_sort:

    • 第一个原型:将范围 [begin, end) 中的前 (middle - begin) 个最小元素进行排序,并存储在 [begin, middle) 中。其余的元素 [middle, end) 保持不变。
    • 第二个原型:将范围 [begin, end) 中的前 (middle - begin) 个最小元素(根据自定义的比较函数 pred)进行排序,并存储在 [begin, middle) 中,其余的元素保持不变。
  • partial_sort_copy:

    • 第一个原型:将范围 [begin, end) 中的前 (dest_end - dest_begin) 个最小元素复制到目标范围 [dest_begin, dest_end) 中。源范围和目标范围的元素个数取较小值。
    • 第二个原型:将范围 [begin, end) 中的前 (dest_end - dest_begin) 个最小元素(根据自定义的比较函数 pred)复制到目标范围 [dest_begin, dest_end) 中。源范围和目标范围的元素个数取较小值。

示例:

#include <algorithm>
#include <iostream>
#include <functional>
#include <iterator>

using namespace std;

int main() {
    int ia[] = {1, 9, 5, 3, 7, 2, 4, 6, 8, 10};
    int ia2[6];

    // 复制范围 [ia, ia + 10) 中的前 6 个最小元素到 ia2
    partial_sort_copy(ia, ia + 10, ia2, ia2 + 6);
    cout << "the 6 smallest elements: ";
    copy(ia2, ia2 + 6, ostream_iterator<int>(cout, " "));
    cout << '\n';

    // 在范围 [ia, ia + 10) 中,将前 3 个最小元素排序到 [ia, ia + 3)
    partial_sort(ia, ia + 3, ia + 10);
    cout << "find the 3 smallest elements:\n";
    copy(ia, ia + 3, ostream_iterator<int>(cout, " "));
    cout << '\n';

    // 在范围 [ia, ia + 10) 中,将前 5 个最大元素排序到 [ia, ia + 5)
    partial_sort(ia, ia + 5, ia + 10, greater<int>());
    cout << "find the 5 largest elements:\n";
    copy(ia, ia + 5, ostream_iterator<int>(cout, " "));
    cout << '\n';

    return 0;
}

输出:

the 6 smallest elements: 1 2 3 4 5 6 
find the 3 smallest elements:
1 2 3 
find the 5 largest elements:
10 9 8 7 6

总结:

  • partial_sort 用于部分排序源范围中的元素,只对前面一部分进行排序,其余元素保持原状。
  • partial_sort_copy 用于将源范围中前面一部分元素(按照指定的排序规则)复制到目标范围,目标范围的大小取决于源范围和目标范围的较小值。

partial_sum

在这里插入图片描述

头文件:

#include <numeric>
#include <algorithm>
#include <iostream>
#include <functional>
#include <iterator>

函数原型:

  • partial_sum:
    OutputIterator partial_sum(InputIterator first, InputIterator last,
                               OutputIterator result);
    
    OutputIterator partial_sum(InputIterator first, InputIterator last,
                               OutputIterator result, BinaryOperation op);
    

描述:

  • 第一个原型:计算范围 [first, last) 的部分和,并将结果存储在 [result, <返回的 OutputIterator>) 中。结果范围的第一个元素等于 first 指向的元素。后续元素是前面元素的累计和。

  • 第二个原型:计算范围 [first, last) 的部分累积,使用二元操作符 op 计算每个元素的值。结果范围的第一个元素等于 first 指向的元素。后续元素是前一个结果元素和当前元素的操作结果。

示例:

#include <numeric>
#include <algorithm>
#include <iostream>
#include <functional>
#include <iterator>

using namespace std;

int main() {
    int ia[] = {1, 2, 3, 4, 5};
    int ia2[5];

    // 计算部分和
    copy(ia2, partial_sum(ia, ia + 5, ia2), ostream_iterator<int>(cout, " "));
    cout << '\n';

    // 使用乘法计算部分积
    copy(ia2, partial_sum(ia, ia + 5, ia2, multiplies<int>()), ostream_iterator<int>(cout, " "));
    cout << '\n';

    return 0;
}

输出:

1 3 6 10 15 
1 2 6 24 120

总结:

  • partial_sum 的第一个原型用于计算指定范围内的部分和,结果从 first 开始,后续的每个元素是之前所有元素的累计和。

  • partial_sum 的第二个原型允许使用自定义的二元操作符 op 来计算部分累积,例如可以用来计算部分积等。

partition / partition_point / stable_partition

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

头文件:

#include <algorithm>

函数原型:

  • partition:

    BidirectionalIterator partition([ExecPol,] BidirectionalIterator first, 
                                    BidirectionalIterator last, 
                                    UnaryPredicate pred);
    
  • stable_partition:

    BidirectionalIterator stable_partition([ExecPol,] BidirectionalIterator first, 
                                            BidirectionalIterator last, 
                                            UnaryPredicate pred);
    
  • partition_point:

    ForwardIterator partition_point(ForwardIterator first, 
                                     ForwardIterator last, 
                                     UnaryPredicate pred);
    

描述:

  • partition:将范围 [first, last) 中所有使得一元谓词 pred 返回 true 的元素移到范围的前面,其余元素放在后面。这个操作并不会保持元素的原始顺序。

  • stable_partition:与 partition 类似,但保持谓词 pred 返回 truefalse 的元素各自的相对顺序。

  • partition_point:返回一个迭代器,指向第一个使得谓词 pred 返回 false 的元素的位置。如果所有元素都使谓词 pred 返回 true,则返回 last

示例:

#include <algorithm>
#include <iostream>
#include <string>
#include <iterator>

using namespace std;

void show(int *begin, int *end) {
    copy(begin, end, ostream_iterator<int>{ cout, " " });
    cout << '\n';
}

int main() {
    int org[] = {1, 3, 5, 7, 9, 10, 2, 8, 6, 4};
    int ia[10];
    copy(org, org + 10, ia);

    auto lessThan4 = [](int value) {
        return value <= 4;
    };

    // 使用 partition
    int *split = partition(ia, ia + 10, lessThan4);
    cout << "Last ia[]- element <= 4 is ia[" << split - ia - 1 << "]\n";
    show(ia, end(ia));

    // 使用 stable_partition
    copy(org, org + 10, ia);
    split = stable_partition(ia, ia + 10, lessThan4);
    cout << "Last org[]-element <= 4 is ia[" << split - ia - 1 << "]\n";
    show(ia, end(ia));

    // 使用 partition_point
    cout << "org[]-elements up to the partition point 4 are:\n";
    show(org, partition_point(org, org + 10, lessThan4));

    return 0;
}

输出:

Last ia[]- element <= 4 is ia[3]
1 3 4 2 9 10 7 8 6 5

Last org[]-element <= 4 is ia[3]
1 3 2 4 5 7 9 10 8 6

org[]-elements up to the partition point 4 are:
1 3

总结:

  • partition:重新排列元素,使得所有满足谓词的元素在前,但不保持原始顺序。

  • stable_partition:类似于 partition,但保持元素的相对顺序。

  • partition_point:返回第一个不满足谓词的元素的迭代器。

partition_copy

在这里插入图片描述

头文件:

#include <algorithm>
#include <string>
#include <iostream>
#include <iterator>

函数原型:

std::pair<ForwardIter2, ForwardIter3> partition_copy([ExecPol,]
ForwardIter1 first, ForwardIter1 last, 
ForwardIter2 trueDest,
ForwardIter3 falseDest, 
UnaryPredicate pred);

描述:

  • 所有在范围 [first, last) 内使得谓词 pred 返回 true 的元素被复制到以 trueDest 开始的范围中,而其余元素被复制到以 falseDest 开始的范围中。范围 [first, last)trueDestfalseDest 的范围不能重叠。

示例:

#include <algorithm>
#include <string>
#include <iostream>
#include <iterator>

using namespace std;

// 定义谓词函数
bool pred(const std::string &str) {
    return "aeiou"s.find(str.front()) != string::npos;
}

// 显示函数
void show(const string *begin, const string *end) {
    copy(begin, end, ostream_iterator<string>(cout, ", "));
    cout << '\n';
}

int main() {
    // 初始化字符串数组
    string sarr[] = {
        "alpha", "bravo", "charley", "delta", "echo",
        "foxtrot", "golf", "hotel"
    };

    // 创建存储分组结果的数组
    string trueDest[size(sarr)];
    string falseDest[size(sarr)];

    // 执行 partition_copy
    pair<string*, string*> lastTF =
        partition_copy(sarr, end(sarr), trueDest, falseDest, pred);

    // 显示结果
    cout << "pred() == true elements:\n";
    show(trueDest, lastTF.first);
    cout << "pred() == false elements:\n";
    show(falseDest, lastTF.second);

    return 0;
}

输出:

pred() == true elements:
alpha, echo,

pred() == false elements:
bravo, charley, delta, foxtrot, golf, hotel,

总结:

  • partition_copy:将范围 [first, last) 内的元素根据谓词 pred 的返回值分别复制到两个目标范围中,一个是满足谓词的元素,另一个是不满足谓词的元素。

reduce 算法

在这里插入图片描述

头文件
#include <numeric>
函数原型
  • Type reduce([ExecPol,] InputIterator first, InputIterator last);
  • Type reduce([ExecPol,] InputIterator first, InputIterator last, Type init);
  • Type reduce([ExecPol,] InputIterator first, InputIterator last, BinaryOperation op);
  • Type reduce([ExecPol,] InputIterator first, InputIterator last, Type init, BinaryOperation op);
描述

reduce 算法类似于 accumulate,但要求所用的操作符必须是结合律和交换律的:对元素的重组和排列顺序不会影响最终结果。例如,数值加法操作符满足这两个要求。

  • 第一个原型:对区间 [first, last) 中的元素应用 operator+,返回结果的和。
  • 第二个原型:对初始值 init (左侧参数) 和区间 [first, last) 中的元素应用二元操作符 op。返回计算结果的和。
  • 最后两个原型:与前两个原型类似,但使用二元操作符 op 替代 operator+。计算时,先将最终返回的变量作为操作符的左侧参数,然后用迭代器区间中的元素作为右侧参数,操作符的返回值将赋值给最终返回的变量。
示例代码
// 编译命令: g++ -O2 reduce.cc -ltbb
#include <numeric>
#include <vector>
#include <execution>
#include <iostream>
using namespace std;

int main()
{
    int ia[] = {1, 2, 3, 4};
    vector<int> iv(ia, ia + 4);

    // 用于演示:对4个值使用并行执行
    cout <<
    "Sum: " << reduce(execution::par, iv.begin(), iv.end(), int()) << "\n"
    "Product: " << reduce(iv.begin(), iv.end(), int(1), multiplies<int>{}) << '\n';
}
输出
Sum: 10
Product: 24

remove, remove_if, remove_copy, remove_copy_if 算法

在这里插入图片描述

头文件
#include <algorithm>
函数原型
  • ForwardIterator remove([ExecPol,] ForwardIterator first, ForwardIterator last, Type const &value);
  • OutputIterator remove_copy([ExecPol,] InputIterator first, InputIterator last, OutputIterator dest, Type const &value);
  • OutputIterator remove_copy_if([ExecPol,] InputIterator first, InputIterator last, OutputIterator dest, UnaryPredicate pred);
  • ForwardIterator remove_if([ExecPol,] ForwardIterator first, ForwardIterator last, UnaryPredicate pred);
描述
  • 第一个原型:将 [first, last) 区间内的元素重新排序,使所有不等于 value 的值位于区间的开头。返回的前向迭代器指向重新排序后可以被移除的第一个元素。范围 [returnvalue, last) 称为算法的剩余部分。注意,剩余部分可能包含不同于 value 的元素,但这些元素可以安全地移除,因为这些元素也出现在 [first, returnvalue) 区间中。这种重复是因为算法是复制而不是移动元素到新位置。函数使用数据类型的 operator== 来确定要移除的元素。

  • 第二个原型:将 [first, last) 区间中不匹配 value 的元素复制到 [dest, returnvalue) 区间,其中 returnvalue 是函数返回的值。原区间 [first, last) 不会被修改。函数使用数据类型的 operator== 来确定哪些元素不需要复制。

  • 第三个原型:对于 [first, last) 区间内的元素,如果一元谓词 pred 返回 true,这些元素不会插入到结果迭代器中。所有其他元素被复制到 [dest, returnvalue) 区间,其中 returnvalue 是函数返回的值。原区间 [first, last) 不会被修改。

  • 第四个原型:将 [first, last) 区间内的元素重新排序,使所有一元谓词 pred 返回 false 的值位于区间的开头,并保持其相对顺序。返回的前向迭代器指向重新排序后一元谓词 pred 返回 true 的第一个元素。范围 [returnvalue, last) 称为算法的剩余部分。剩余部分可能包含一元谓词 pred 返回 false 的元素,但这些元素可以安全地移除,因为这些元素也出现在 [first, returnvalue) 区间中。这种重复是因为算法是复制而不是移动元素到新位置。

注意,复制重载函数期望输出迭代器。如果要保留的元素存储在例如 vector 中,则可以将 kept.begin() 作为函数的 dest 参数。然而,这要求在调用函数之前 size(kept) 必须足够大以容纳所有保留的元素。另一种方法是使用 back_inserter 确保 kept 在函数返回后仅包含保留的元素。这种方法在示例程序中使用。

示例代码
#include <algorithm>
#include <iostream>
#include <string>
#include <iterator>
#include <vector>
using namespace std;

using StrVect = vector<string>;

bool judge(string const &word)
{
    return count(word.begin(), word.end(), 'a') > 1;
}

void show(auto const &begin, auto const &end)
{
    copy(begin, end, ostream_iterator<string>(cout, ", "));
    cout << "\n";
}

int main()
{
    StrVect words =
    {
        "kilo", "alpha", "lima", "mike", "alpha", "november",
        "alpha", "alpha", "alpha", "papa", "quebec"
    };

    auto src{ words };

    cout << "Removing all \"alpha\"s:\n";
    auto end = remove(src.begin(), src.end(), "alpha");
    show(src.begin(), end);
    cout << "Leftover elements are:\n";
    show(end, src.end());

    src = words;
    cout << "Remove_copy_if removes words having > 1 'a' chars:\n";
    StrVect kept;
    remove_copy_if(src.begin(), src.end(), back_inserter(kept), judge);
    show(kept.begin(), kept.end());
}
输出
Removing all "alpha"s:
kilo, lima, mike, november, papa, quebec,
Leftover elements are:
alpha, alpha, alpha,

Remove_copy_if removes words having > 1 'a' chars:
kilo, lima, mike, november, quebec,

replace, replace_if, replace_copy, replace_copy_if 算法

在这里插入图片描述

头文件
#include <algorithm>
函数原型
  • void replace([ExecPol,] ForwardIterator first, ForwardIterator last, Type const &oldvalue, Type const &newvalue);
  • ForwardIterator replace_if([ExecPol,] ForwardIterator first, ForwardIterator last, UnaryPredicate pred, Type const &value);
  • OutputIterator replace_copy([ExecPol,] InputIterator first, InputIterator last, OutputIterator result, Type const &oldvalue, Type const &newvalue);
  • OutputIterator replace_copy_if([ExecPol,] ForwardIterator first, ForwardIterator last, OutputIterator result, UnaryPredicate pred, Type const &value);
描述
  • 第一个原型:将 [first, last) 区间内所有等于 oldvalue 的元素替换为 newvalue 的副本。算法使用数据类型的 operator== 来比较元素。

  • 第二个原型:将 [first, last) 区间内一元谓词 pred 返回 true 的元素替换为 value

  • 第三个原型:将 [first, last) 区间内所有等于 oldvalue 的元素替换为 newvalue,并将结果发送到输出迭代器 result 中。算法使用数据类型的 operator== 来比较元素。

  • 第四个原型:将 [first, last) 区间内一元谓词 pred 返回 false 的元素发送到结果输出迭代器中,如果 pred 返回 true,则将 value 发送到结果输出迭代器中。原区间 [first, last) 不会被修改。

示例代码
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
using namespace std;

using StrVect = vector<string>;

void show(StrVect const &vect)
{
    copy(vect.begin(), vect.end(), ostream_iterator<string>(cout, " "));
    cout.put('\n');
}

bool isAlpha(string const &str)
{
    return str == "alpha";
}

int main()
{
    StrVect words =
    {
        "kilo", "alpha", "lima", "mike", "alpha", "november",
        "alpha", "oscar", "alpha", "alpha", "papa"
    };

    // 使用 replace 替换 "alpha" 为 "ALPHA"
    // replace(words.begin(), words.end(), "alpha"s, "ALPHA"s);
    // show(words);

    // 使用 replace_if 替换符合谓词的元素
    // replace_if(words.begin(), words.end(), isAlpha, "ALPHA"s);
    // show(words);

    // 使用 replace_copy 生成新的结果容器
    // StrVect result;
    // replace_copy(words.begin(), words.end(), back_inserter(result), "alpha"s, "ALPHA"s);
    // show(result);

    // 使用 replace_copy_if 生成新的结果容器
    StrVect result;
    replace_copy_if(words.begin(), words.end(), back_inserter(result), isAlpha, "ALPHA"s);
    show(result);
}
输出
kilo ALPHA lima mike ALPHA november ALPHA oscar ALPHA ALPHA papa

reverse, reverse_copy 算法

在这里插入图片描述

头文件
#include <algorithm>
函数原型
  • void reverse([ExecPol,] BidirectionalIterator first, BidirectionalIterator last);
  • OutputIterator reverse_copy([ExecPol,] BidirectionalIterator first, BidirectionalIterator last, OutputIterator dest);
描述
  • 第一个原型:将 [first, last) 区间内的元素顺序反转。

  • 第二个原型:将 [first, last) 区间内的元素以反转顺序插入到 dest 中,返回最后一个插入元素后的输出迭代器。

示例代码
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
using namespace std;

using StrVect = vector<string>;

void show(StrVect const &vect)
{
    copy(vect.begin(), vect.end(), ostream_iterator<string>(cout, " "));
    cout.put('\n');
}

int main(int argc, char **argv)
{
    StrVect words =
    {
        "alpha", "kilo", "lima", "mike",
        "november", "oscar", "papa"
    };

    if (argc == 1) {
        // 没有参数:直接反转
        reverse(words.begin(), words.end());
        show(words);
        return 0;
    }

    StrVect dest;
    reverse_copy(words.begin(), words.end(), back_inserter(dest));
    show(dest);
}
输出
papa oscar november mike lima kilo alpha

rotate, rotate_copy 算法

在这里插入图片描述

头文件
#include <algorithm>
函数原型
  • void rotate([ExecPol,] ForwardIterator first, ForwardIterator middle, ForwardIterator last);
  • OutputIterator rotate_copy([ExecPol,] ForwardIterator first, ForwardIterator middle, ForwardIterator last, OutputIterator result);
描述
  • 第一个原型:将区间 [first, middle) 的元素移动到容器的末尾,将区间 [middle, last) 的元素移动到容器的开头,同时保持这两个子区间内元素的顺序不变。

  • 第二个原型:将区间 [middle, last) 的元素,然后是区间 [first, middle) 的元素,按照顺序插入到 result 中,返回最后一个插入元素后的输出迭代器。源区间的元素顺序不会被改变。

示例代码
#include <algorithm>
#include <iostream>
#include <string>
#include <iterator>
#include <vector>
using namespace std;

using StrVect = vector<string>;

void show(StrVect const &vect)
{
    copy(vect.begin(), vect.end(), ostream_iterator<string>(cout, " "));
    cout.put('\n');
}

int main(int argc, char **argv)
{
    StrVect words =
    {
        "kilo", "lima", "mike", "november", "oscar",
        "foxtrot", "golf", "hotel", "india", "juliet"
    };

    if (argc == 1) {
        // 没有参数:直接旋转
        rotate(words.begin(), words.begin() + words.size() / 2, words.end());
        show(words);
        return 0;
    }

    StrVect dest;
    rotate_copy(words.begin(), words.begin() + words.size() / 2, words.end(), back_inserter(dest));
    show(dest);
}
输出
foxtrot golf hotel india juliet kilo lima mike november oscar

sample 算法

在这里插入图片描述

头文件
#include <algorithm>
#include <random>
函数原型
OutputIterator sample(InputIterator first, InputIterator last, OutputIterator out, size_t sampleSize, Generator &&generator);
描述
  • 从输入区间 [first, last) 中随机选择 sampleSize 个元素(不重复),并将它们复制到目标区间,目标区间从 out 开始,到函数的返回值结束。如果 sampleSize 大于或等于 last - first,则选择所有元素。generator 是一个(均匀的)随机数生成器,比如 mt19937
示例代码
#include <algorithm>
#include <iostream>
#include <random>
#include <string>
using namespace std;

int main()
{
    string src{ "abcdefghijklmnopqrstuvwxyz" };
    string dest;

    // 从 src 中随机选择 7 个字母
    sample(src.begin(), src.end(), back_inserter(dest), 7, mt19937{});

    cout << "从 " << src << " 中随机选择的七个字母是: " << dest << '\n';
}
输出示例
从 abcdefghijklmnopqrstuvwxyz 中随机选择的七个字母是: bciorux

search, search_n 算法

在这里插入图片描述

在这里插入图片描述

头文件
#include <algorithm>
函数原型
  • ForwardIterator search([ExecPol,] ForwardIterator first1, ForwardIterator last1, ForwardIterator first2, ForwardIterator last2);
  • ForwardIterator search([ExecPol,] ForwardIterator first1, ForwardIterator last1, ForwardIterator first2, ForwardIterator last2, BinaryPredicate pred);
  • constexpr ForwardIterator search([ExecPol,] ForwardIterator first, ForwardIterator last, Searcher const &searcher);
  • ForwardIterator search_n([ExecPol,] ForwardIterator first, ForwardIterator last, Size count, Type const &value);
  • ForwardIterator search_n([ExecPol,] ForwardIterator first1, ForwardIterator last1, Size count, Type const &value, BinaryPredicate pred);
描述
  • 第一个原型:返回一个迭代器指向 first1last1 范围中第一个找到的 [first2, last2) 区间的开始位置。如果没有找到,则返回 last1

  • 第二个原型:与第一个原型类似,但使用提供的二元谓词 pred 来比较两个区间的元素。如果没有找到,则返回 last1

  • 第三个原型:使用 searcherfirstlast 范围执行搜索,searcher 接收这个范围,并返回找到的迭代器(如果没有找到,则返回 last)。

  • 第四个和第五个原型:检查 [first, last) 范围内是否存在一个长度为 count 的序列,其中每个元素都等于 value。返回第一个符合条件的迭代器。如果没有找到,则返回 last。第五个原型使用谓词 pred 来判断元素是否等于 value

示例代码
#include <algorithm>
#include <iostream>
#include <iterator>
using namespace std;

bool absEq(int i1, int i2)
{
    return abs(i1) == abs(i2);
}

int main()
{
    int range1[] = {-2, -4, -6, -8, 2, 4, 4, 6, 8};
    int range2[] = {6, 8};

    copy(
        search(range1, end(range1), range2, range2 + 2),
        end(range1),
        ostream_iterator<int>(cout, " ")
    );
    cout << '\n';

    copy(
        search(range1, end(range1), range2, range2 + 2, absEq),
        end(range1),
        ostream_iterator<int>(cout, " ")
    );
    cout << '\n';

    copy(
        search_n(range1, end(range1), 2, 4, absEq),
        end(range1),
        ostream_iterator<int>(cout, " ")
    );
    cout << '\n';
}
输出
6 8
-6 -8 2 4 4 6 8
4 4 6 8

set_difference 算法

在这里插入图片描述

头文件
#include <algorithm>
函数原型
  • OutputIterator set_difference([ExecPol,] InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result);
  • OutputIterator set_difference([ExecPol,] InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp);
描述
  • 第一个原型:从 [first1, last1) 范围中选择那些不在 [first2, last2) 范围中的元素,并将它们按排序顺序放置在 result 开始的位置。两个范围中的元素必须已经按 operator< 排序。

  • 第二个原型:与第一个原型类似,但使用比较函数对象 comp 来比较两个范围中的元素。两个范围中的元素必须按照 comp 排序。

示例代码
#include <algorithm>
#include <iostream>
#include <string>
#include <cstring>
#include <iterator>
using namespace std;

bool caseless(string const &left, string const &right)
{
    return strcasecmp(left.c_str(), right.c_str()) < 0;
}

int main()
{
    string set1[] = { "kilo", "lima", "mike", "november", "oscar", "papa", "quebec" };
    string set2[] = { "papa", "quebec", "romeo" };
    string result[7];

    // 查找 set1 中不在 set2 中的元素
    copy(
        result,
        set_difference(set1, set1 + 7, set2, set2 + 3, result),
        ostream_iterator<string>(cout, " ")
    );
    cout << '\n';

    string set3[] = { "PAPA", "QUEBEC", "ROMEO" };

    // 查找 set1 中不在 set3 中的元素,忽略大小写
    copy(
        result,
        set_difference(set1, set1 + 7, set3, set3 + 3, result, caseless),
        ostream_iterator<string>(cout, " ")
    );
    cout << '\n';
}
输出
kilo lima mike november oscar
kilo lima mike november oscar

set_intersection 算法

在这里插入图片描述

头文件
#include <algorithm>
函数原型
  • OutputIterator set_intersection([ExecPol,] InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result);
  • OutputIterator set_intersection([ExecPol,] InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp);
描述
  • 第一个原型:从 [first1, last1) 范围中选择那些也存在于 [first2, last2) 范围中的元素,并将它们按排序顺序放置在 result 开始的位置。两个范围中的元素必须已经按照 operator< 排序。

  • 第二个原型:与第一个原型类似,但使用比较函数对象 comp 来比较两个范围中的元素。两个范围中的元素必须按照 comp 排序。

示例代码
#include <algorithm>
#include <iostream>
#include <string>
#include <cstring>
#include <iterator>
using namespace std;

bool caseless(string const &left, string const &right)
{
    return strcasecmp(left.c_str(), right.c_str()) < 0;
}

int main()
{
    string set1[] = { "kilo", "lima", "mike", "november", "oscar", "papa", "quebec" };
    string set2[] = { "papa", "quebec", "romeo" };
    string result[7];

    // 查找 set1 和 set2 中的交集
    copy(
        result,
        set_intersection(set1, set1 + 7, set2, set2 + 3, result),
        ostream_iterator<string>(cout, " ")
    );
    cout << '\n';

    string set3[] = { "PAPA", "QUEBEC", "ROMEO" };

    // 查找 set1 和 set3 中的交集,忽略大小写
    copy(
        result,
        set_intersection(set1, set1 + 7, set3, set3 + 3, result, caseless),
        ostream_iterator<string>(cout, " ")
    );
    cout << '\n';
}
输出
papa quebec
papa quebec

set_symmetric_difference 算法

在这里插入图片描述

头文件
#include <algorithm>
函数原型
  • OutputIterator set_symmetric_difference([ExecPol,] InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result);
  • OutputIterator set_symmetric_difference([ExecPol,] InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp);
描述
  • 第一个原型:返回 [first1, last1) 范围内存在但不在 [first2, last2) 范围内的元素,以及 [first2, last2) 范围内存在但不在 [first1, last1) 范围内的元素,按排序顺序存放在 result 开始的位置。两个范围中的元素必须已经按照 operator< 排序。

  • 第二个原型:与第一个原型类似,但使用比较函数对象 comp 来比较两个范围中的元素。两个范围中的元素必须按照 comp 排序。

示例代码
#include <algorithm>
#include <iostream>
#include <string>
#include <cstring>
#include <iterator>
using namespace std;

bool caseless(string const &left, string const &right)
{
    return strcasecmp(left.c_str(), right.c_str()) < 0;
}

int main()
{
    string set1[] = { "kilo", "lima", "mike", "november", "oscar", "papa", "quebec" };
    string set2[] = { "papa", "quebec", "romeo" };
    string result[7];

    // 查找 set1 和 set2 中的对称差集
    copy(
        result,
        set_symmetric_difference(set1, set1 + 7, set2, set2 + 3, result),
        ostream_iterator<string>(cout, " ")
    );
    cout << '\n';

    string set3[] = { "PAPA", "QUEBEC", "ROMEO" };

    // 查找 set1 和 set3 中的对称差集,忽略大小写
    copy(
        result,
        set_symmetric_difference(set1, set1 + 7, set3, set3 + 3, result, caseless),
        ostream_iterator<string>(cout, " ")
    );
    cout << '\n';
}
输出
kilo lima mike november oscar romeo
kilo lima mike november oscar ROMEO

set_union 算法

在这里插入图片描述

头文件
#include <algorithm>
函数原型
  • OutputIterator set_union([ExecPol,] InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result);
  • OutputIterator set_union([ExecPol,] InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp);
描述
  • 第一个原型:返回 [first1, last1) 范围内与 [first2, last2) 范围内的元素的并集,按排序顺序存放在 result 开始的位置。两个范围中的元素必须已经按照 operator< 排序。

  • 第二个原型:与第一个原型类似,但使用比较函数对象 comp 来比较两个范围中的元素。两个范围中的元素必须按照 comp 排序。最终的结果中每个元素只出现一次,除非源范围内有重复元素,则结果中也会保留这些重复元素。

示例代码
#include <algorithm>
#include <iostream>
#include <string>
#include <cstring>
#include <iterator>
#include <vector>
using namespace std;

bool caseless(string const &left, string const &right)
{
    return strcasecmp(left.c_str(), right.c_str()) < 0;
}

int main()
{
    string set1[] = { "kilo", "lima", "mike", "november", "oscar", "papa", "quebec" };
    string set2[] = { "papa", "quebec", "romeo" };
    string result[8];

    // 查找 set1 和 set2 中的并集
    copy(
        result,
        set_union(set1, set1 + 7, set2, set2 + 3, result),
        ostream_iterator<string>(cout, " ")
    );
    cout << '\n';

    string set3[] = { "PAPA", "QUEBEC", "ROMEO" };

    // 查找 set1 和 set3 中的并集,忽略大小写
    copy(
        result,
        set_union(set1, set1 + 7, set3, set3 + 3, result, caseless),
        ostream_iterator<string>(cout, " ")
    );
    cout << '\n';

    std::vector<int> v1 = {1, 2, 3, 4, 5, 5, 5};
    std::vector<int> v2 = {3, 3, 3, 4, 5, 6, 7};

    // 查找 v1 和 v2 中的并集
    set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), ostream_iterator<int>(cout, " "));
    cout << '\n';
}
输出
kilo lima mike november oscar papa quebec romeo
kilo lima mike november oscar papa quebec ROMEO
1 2 3 3 3 4 5 5 5 6 7

sortstable_sort 算法

在这里插入图片描述

头文件
#include <algorithm>
函数原型
  • void sort([ExecPol,] RandomAccessIterator first, RandomAccessIterator last);
  • void sort([ExecPol,] RandomAccessIterator first, RandomAccessIterator last, Compare comp);
  • void stable_sort([ExecPol,] RandomAccessIterator first, RandomAccessIterator last);
  • void stable_sort([ExecPol,] RandomAccessIterator first, RandomAccessIterator last, Compare comp);
描述
  • 第一个原型:对 [first, last) 范围内的元素进行升序排序,使用 operator< 进行比较。

  • 第二个原型:对 [first, last) 范围内的元素进行升序排序,使用 comp 函数对象进行比较。comp 应返回 true,如果第一个参数在排序序列中应排在第二个参数之前。

  • 第三个和第四个原型:与前两个原型相同,但使用稳定排序,保持相等元素的初始顺序不变。

示例代码
// 编译方式: g++ -O2 sort.cc -ltbb
#include <algorithm>
#include <cstdlib>
#include <execution>
#include <functional>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

using namespace std;

int main() {
    string words[] = {"november", "kilo", "mike", "lima", "oscar", "quebec", "papa"};

    // 使用默认的升序排序
    sort(words, words + 7);
    copy(words, words + 7, ostream_iterator<string>(cout, " "));
    cout << '\n';

    // 使用降序排序
    sort(words, words + 7, greater<string>());
    copy(words, words + 7, ostream_iterator<string>(cout, " "));
    cout << '\n';

    // 随机生成 10,000 个整数并排序
    int *vect = new int[10'000];
    generate(execution::par, vect, vect + 10'000, rand);
    cout << "sorted: " << is_sorted(vect, vect + 10'000) << '\n';
    sort(execution::par, vect, vect + 10'000);
    cout << "sorted: " << is_sorted(vect, vect + 10'000) << '\n';
    delete[] vect;

    // 稳定排序
    using Pair = pair<size_t, string>;  // 天数与月份
    vector<Pair> months = {
        {31, "Jan."}, {28, "Feb."}, {31, "Mar."}, {30, "Apr."},
        {31, "May."}, {30, "Jun."}, {31, "Jul."}, {31, "Aug."},
        {30, "Sep."}, {31, "Oct."}, {30, "Nov."}, {31, "Dec."}
    };

    stable_sort(months.begin(), months.end(),
                [&](Pair const &lhs, Pair const &rhs) {
                    return lhs.first > rhs.first;
                });

    for (size_t idx = 0; auto const &month : months) {
        cout << month.first << ": " << month.second
             << (++idx % 4 == 0 ? "\n" : " ");
    }
}
输出
kilo lima mike november oscar papa quebec
quebec papa oscar november mike lima kilo
sorted: 0  // unordered sequence
sorted: 1  // sorted sequence
31: Jan. 31: Mar. 31: May. 31: Jul.
31: Aug. 31: Oct. 31: Dec. 30: Apr.
30: Jun. 30: Sep. 30: Nov. 28: Feb.

在示例中,还展示了如何使用 execution::par 执行策略来并行生成和排序整数数组。

shift_leftshift_right 算法

在这里插入图片描述

头文件
#include <algorithm>
函数原型
  • ForwardIterator shift_left(ForwardIterator first, ForwardIterator last, ForwardIterator new_first);
  • ForwardIterator shift_right(ForwardIterator first, ForwardIterator last, ForwardIterator new_last);
描述
  • shift_left:将 [first, last) 范围内的元素向左移动,使得 [first, new_first) 范围内的元素被移动到 [new_first, last) 范围的末尾。移动后,new_first[first, new_first) 之间的元素会被填补 new_first 后面的空位。返回 new_first 的位置。

  • shift_right:将 [first, last) 范围内的元素向右移动,使得 [last - (new_last - first), last) 范围内的元素被移动到 [first, new_last) 范围的前面。移动后,new_last[last - (new_last - first), last) 之间的元素会被填补到 new_last 前面的空位。返回 new_last 的位置。

示例代码
#include <algorithm>
#include <iostream>
#include <vector>
#include <iterator>

using namespace std;

int main() {
    vector<int> v1 = {1, 2, 3, 4, 5, 6, 7, 8, 9};

    // 使用 shift_left 将元素向左移动
    auto new_first1 = shift_left(v1.begin(), v1.begin() + 4, v1.end());
    copy(v1.begin(), v1.end(), ostream_iterator<int>(cout, " "));
    cout << "\nnew_first1 position: " << distance(v1.begin(), new_first1) << '\n';

    // 使用 shift_right 将元素向右移动
    vector<int> v2 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    auto new_last2 = shift_right(v2.begin(), v2.end(), v2.begin() + 5);
    copy(v2.begin(), v2.end(), ostream_iterator<int>(cout, " "));
    cout << "\nnew_last2 position: " << distance(v2.begin(), new_last2) << '\n';

    return 0;
}
输出
5 6 7 8 9 1 2 3 4 
new_first1 position: 5

5 6 7 8 9 1 2 3 4 
new_last2 position: 5

说明

  • shift_left 示例中,{1, 2, 3, 4} 被移到 v1 的末尾,剩余的 {5, 6, 7, 8, 9} 被移动到前面。
  • shift_right 示例中,{5, 6, 7, 8, 9} 被移到 v2 的前面,剩余的 {1, 2, 3, 4} 被移动到后面。

shuffle 算法

在这里插入图片描述

头文件
#include <algorithm>
#include <random>
函数原型
  • template<class RandomAccessIterator, class RandomGenerator>
    void shuffle(RandomAccessIterator first, RandomAccessIterator last, RandomGenerator&& g);
描述
  • shuffle:打乱 [first, last) 范围内元素的顺序。RandomGenerator 是一个随机数生成器(通常是 std::mt19937std::default_random_engine),用于生成随机索引,以便重新排列元素。
示例代码
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
#include <random>

using namespace std;

int main() {
    // 创建一个包含整数的 vector
    vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9};

    // 使用 std::random_device 和 std::mt19937 作为随机数生成器
    random_device rd;
    mt19937 g(rd());

    // 打乱 vector 中的元素
    shuffle(v.begin(), v.end(), g);

    // 打印打乱后的元素
    copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
    cout << '\n';

    return 0;
}
输出
3 8 1 6 5 9 4 7 2

说明

  • shuffle 函数通过使用随机数生成器 g[first, last) 范围内的元素进行打乱。
  • 每次运行程序时,输出的元素顺序都可能不同,因为 shuffle 使用了随机生成器。
注意事项
  • 要确保提供的 RandomGenerator 是有效的,并且能够生成足够的随机数来打乱元素。std::mt19937 是一种常用的选择。
  • shuffle 是就地打乱,不会创建新的容器,而是修改原容器中的元素顺序。

short_heap 算法

在这里插入图片描述

头文件
#include <algorithm>
函数原型
  • template<class RandomAccessIterator, class Compare>
    void make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp);

  • template<class RandomAccessIterator>
    void make_heap(RandomAccessIterator first, RandomAccessIterator last);

  • template<class RandomAccessIterator, class Compare>
    void push_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp);

  • template<class RandomAccessIterator>
    void push_heap(RandomAccessIterator first, RandomAccessIterator last);

  • template<class RandomAccessIterator, class Compare>
    void pop_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp);

  • template<class RandomAccessIterator>
    void pop_heap(RandomAccessIterator first, RandomAccessIterator last);

  • template<class RandomAccessIterator, class Compare>
    void sort_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp);

  • template<class RandomAccessIterator>
    void sort_heap(RandomAccessIterator first, RandomAccessIterator last);

描述
  • make_heap: 将 [first, last) 范围内的元素重新排列为一个堆(heap)。默认情况下使用 operator<,可以通过传入比较函数来指定自定义的堆顺序。

  • push_heap: 将新元素加入堆中并调整堆以保持堆性质。last 参数是新元素的结束迭代器。

  • pop_heap: 从堆中删除最大(或最小)元素,并调整堆。last 参数是当前堆的结束迭代器,删除的元素将位于 last-1

  • sort_heap: 将堆排序为一个有序的序列。可以使用自定义的比较函数进行排序。

示例代码
#include <algorithm>
#include <iostream>
#include <vector>

using namespace std;

int main() {
    vector<int> v = {20, 10, 30, 5, 1, 15};
    
    // 创建堆
    make_heap(v.begin(), v.end());
    cout << "Initial heap: ";
    for (int n : v) cout << n << " ";
    cout << '\n';

    // 向堆中添加元素
    v.push_back(25);
    push_heap(v.begin(), v.end());
    cout << "Heap after push: ";
    for (int n : v) cout << n << " ";
    cout << '\n';

    // 从堆中删除元素
    pop_heap(v.begin(), v.end());
    v.pop_back();
    cout << "Heap after pop: ";
    for (int n : v) cout << n << " ";
    cout << '\n';

    // 堆排序
    sort_heap(v.begin(), v.end());
    cout << "Sorted heap: ";
    for (int n : v) cout << n << " ";
    cout << '\n';

    return 0;
}
输出
Initial heap: 30 20 15 5 10 1 
Heap after push: 30 20 25 5 10 1 15 
Heap after pop: 25 20 15 5 10 1 
Sorted heap: 1 5 10 15 20 25 
说明
  • make_heap 将一个序列转换为堆。
  • push_heappop_heap 用于在堆中添加和删除元素,并保持堆的性质。
  • sort_heap 将堆排序为有序序列。
注意事项
  • 使用 std::greater 作为比较函数可以创建一个小根堆(最小值在顶部)。
  • 堆操作的时间复杂度为 O(log N),而 sort_heap 的时间复杂度为 O(N log N)。

swap / swap_ranges 算法

在这里插入图片描述

头文件
#include <algorithm>
函数原型
  • void swap(Type &object1, Type &object2) noexcept;

  • void swap(Type (&object1)[N], Type (&object2)[N]) noexcept;

  • ForwardIterator2 swap_ranges([ExecPol,] ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 result);

描述
  • 第一个原型: 交换 object1object2 的值。交换可以通过循环拷贝赋值或循环移动赋值(如果可用)来实现。

  • 第二个原型: 交换 object1object2 两个数组中的元素,数组大小在编译时已知。

  • 第三个原型: 将 [first1, last1) 范围中的元素与 [result, result + (last1 - first1)) 范围中的元素交换,函数返回值为 result + (last1 - first1)。这两个范围必须是互不重叠的。

示例代码
#include <algorithm>
#include <iostream>
#include <string>
#include <iterator>

using namespace std;

void show(string const *begin, string const *end) {
    copy(begin, end, ostream_iterator<string>(cout, " "));
    cout << '\n';
}

int main() {
    string first[] = { "alpha", "bravo", "charley" };
    string second[] = { "echo", "foxtrot", "golf" };

    cout << "Before:\n";
    show(first, end(first));
    show(second, end(second));

    // 逐个交换
    for (size_t idx = 0; idx < size(first); ++idx)
        swap(first[idx], second[idx]);

    cout << "After:\n";
    show(first, end(first));
    show(second, end(second));

    // 使用 swap_ranges 交换整个范围
    swap_ranges(first, end(first), second);

    cout << "After swap_ranges:\n";
    show(first, end(first));
    show(second, end(second));

    return 0;
}
输出
Before:
alpha bravo charley
echo foxtrot golf
After:
echo foxtrot golf
alpha bravo charley
After swap_ranges:
alpha bravo charley
echo foxtrot golf
说明
  • swap: 用于交换两个对象或两个相同大小的数组的值。
  • swap_ranges: 用于交换两个范围内的元素,范围长度相同,并且这两个范围必须是不重叠的。

通过使用这些算法,可以方便地交换数据,简化代码逻辑。

transform 算法

在这里插入图片描述

头文件
#include <algorithm>
函数原型
  • OutputIterator transform([ExecPol,] InputIterator first, InputIterator last, OutputIterator result, UnaryOperator op);

  • OutputIterator transform([ExecPol,] InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, OutputIterator result, BinaryOperator op);

描述
  • 第一个原型: 对范围 [first, last) 中的每个元素应用一元操作符 op,并将结果存储到从 result 开始的范围中。函数返回值指向生成元素的最后一个元素之后的位置。

  • 第二个原型: 对范围 [first1, last1) 中的每个元素和从 first2 开始的第二个范围中的对应元素应用二元操作符 op,将结果存储到从 result 开始的范围中。函数返回值指向生成元素的最后一个元素之后的位置。

示例代码
#include <algorithm>
#include <iostream>
#include <string>
#include <cctype>
#include <iterator>
#include <vector>
#include <functional>

using namespace std;

string caps(string const &src) {
    string tmp;
    tmp.resize(src.length());
    transform(src.begin(), src.end(), tmp.begin(), ::toupper);
    return tmp;
}

int main() {
    string words[] = {"alpha", "bravo", "charley"};
    copy(words, transform(words, words + 3, words, caps), ostream_iterator<string>(cout, " "));
    cout << '\n';

    int values[] = {1, 2, 3, 4, 5};
    vector<int> squares;
    transform(values, values + 5, back_inserter(squares), multiplies<int>());
    copy(squares.begin(), squares.end(), ostream_iterator<int>(cout, " "));
    cout << '\n';

    return 0;
}
输出
ALPHA BRAVO CHARLEY
1 4 9 16 25
说明
  • transform:

    • 使用一元操作符 op 对每个元素进行转换,并将结果存储到目标范围中。
    • 使用二元操作符 op 对两个范围内的对应元素进行操作,将结果存储到目标范围中。
  • for_each 的区别:

    • transform 使用函数对象的返回值来生成新的元素,而不修改传递给函数对象的原始值。
    • for_each 则直接修改传递给函数对象的引用参数。
  • 范围基础的 for 循环:

    • 可以用来代替 transform 算法,但 transform 也可以用于子范围和反向迭代器的情况。

transform_reduce 算法

在这里插入图片描述

头文件
#include <numeric>
函数原型
  • Type transform_reduce([ExecPol,] InputIterator first1, InputIterator last1, InputIterator first2, Type value);

  • Type transform_reduce([ExecPol,] InputIterator first1, InputIterator last1, InputIterator first2, Type value, BinaryOperation reduce, BinaryOperation transform);

  • Type transform_reduce([ExecPol,] InputIterator first1, InputIterator last1, Type value, BinaryOperation reduce, UnaryOperation transform);

描述
  • 第一个原型: 等同于第二个原型,使用 std::plus<> 作为 reduce 二元操作符,使用 std::multiplies<> 作为 transform 二元操作符。它也等同于 inner_product 的并行版本。

  • 第二个原型: 将 transform 二元操作符应用于范围 [first1, last1) 中的每个元素(作为左操作数)和从 first2 开始的范围中的对应元素(作为右操作数)。将计算结果作为右操作数,以 value 作为左操作数应用 reduce 二元操作符,最终返回 reduce 的结果。

  • 第三个原型: 将 transform 应用于范围 [first1, last1) 中的每个元素,然后将 value 和每个通过 transform 返回的值传递给 reduce,最终返回 reduce 的结果。

示例代码
#include <numeric>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <string>

using namespace std;

class Cat {
    std::string d_sep;
public:
    Cat(string const &sep) : d_sep(sep) {}

    string operator()(string const &s1, string const &s2) const {
        return s1 + d_sep + s2;
    }
};

int main() {
    size_t ia1[] = {1, 2, 3, 4, 5, 6, 7}; // 用于代替 inner_product:
    cout << "The sum of all squares in ";
    copy(ia1, ia1 + 7, ostream_iterator<size_t>{cout, " "});
    cout << "is " << transform_reduce(ia1, ia1 + 7, ia1, 0) << '\n';

    size_t ia2[] = {7, 6, 5, 4, 3, 2, 1};
    cout << "The sum of all cross-products in ";
    copy(ia1, ia1 + 7, ostream_iterator<size_t>{cout, " "});
    cout << "and ";
    copy(ia2, ia2 + 7, ostream_iterator<size_t>{cout, " "});
    cout << "is " << transform_reduce(ia1, ia1 + 7, ia2, 0) << '\n';

    string names1[] = {"Frank", "Karel", "Piet"};
    string names2[] = {"Brokken", "Kubat", "Plomp"};
    cout << "All combined names of ";
    copy(names1, names1 + 3, ostream_iterator<string>{cout, " "});
    cout << "and ";
    copy(names2, names2 + 3, ostream_iterator<string>{cout, " "});
    cout << "are: " <<
        transform_reduce(names1, names1 + 3, names2, "\t"s,
                         Cat{ "\n\t"}, Cat{ " " }) << '\n';

    return 0;
}
输出
The sum of all squares in 1 2 3 4 5 6 7 is 140
The sum of all cross-products in 1 2 3 4 5 6 7 and 7 6 5 4 3 2 1 is 84
All combined names of Frank Karel Piet and Brokken Kubat Plomp are:
Frank Brokken
Karel Kubat
Piet Plomp
说明
  • transform_reduce:

    • 第一个原型和第二个原型通过使用 std::plus<>std::multiplies<> 进行加法和乘法操作,实现了类似 inner_product 的功能。
    • 第二个原型允许用户自定义 reducetransform 操作符。
    • 第三个原型允许在对输入范围进行 transform 操作后,将 value 和结果传递给 reduce
  • for_eachtransform 的区别:

    • transform_reduce 结合了 transformreduce 操作,可以更高效地处理需要同时应用转换和归约的情况。

处理未初始化的内存

概述

如第9.1.5节所述,placement new 操作符用于在“原始内存”中安装值或对象,即内存已经可用但尚未初始化为预期的对象类型。在使用 auto ptr = new string{ "hello" } 时,字符串在专门分配给该对象的内存中构造,且对象类型的构造函数会在该内存中初始化对象。调用 delete ptr 时,字符串的析构函数会被调用,然后返回内存到通用内存池。

使用 placement new 时,存储对象的内存已经可用,通过 auto ptr = new (storageAddress) string{ "hello" } 仅在指定的 storageAddress 位置构造字符串。字符串可以通过 ptr 访问,但不能使用 delete ptr,因为 storageAddress 位置的内存已在调用 placement new 操作符之前可用。因此,在这些情况下,需要显式调用对象的析构函数(使用 ptr->~string()),而使用 delete ptr 是完全错误的,会导致内存错误并中止程序。

处理未初始化内存的通用算法

使用 placement new 时,可以使用以下通用算法来简化操作。这些算法在 <memory> 头文件中定义,支持执行策略,并提供了复制、填充、初始化和移动对象到/从未初始化(原始)内存的功能,以及删除存储在原始内存中的对象的功能。

  • uninitialized_copy([ExecPol,] ForwardIterator first, ForwardIterator last, ForwardIterator dest)
    [first, last) 范围内的元素复制到从 dest 开始的原始内存中,返回超出最后一个复制元素的位置。

  • uninitialized_copy_n([ExecPol,] ForwardIterator first, size_t nObjects, ForwardIterator dest)
    与上述算法相同,但复制 nObjects 个元素。

  • uninitialized_default_construct([ExecPol,] ForwardIterator first, ForwardIterator last)
    [first, last) 范围内的原始内存位置安装默认构造的值。要求迭代器所指的类型要么是平凡类型(如内建类型),要么定义了 value_type 返回其类型名称。对于平凡类型,安装的值不假定是 0 初始化的。

  • uninitialized_default_construct_n([ExecPol,] ForwardIterator first, size_t nObjects)
    与上述算法相同,但在未初始化的内存中安装 nObjects 个值。

  • uninitialized_fill([ExecPol,] ForwardIterator first, ForwardIterator last, Type const &value)
    uninitialized_copy 相似,但在未初始化内存中安装 value 的副本。

  • uninitialized_fill([ExecPol,] ForwardIterator first, size_t nObjects, Type const &value)
    与上述算法相同,但将 value 复制到未初始化内存中的 nObjects 个后续位置。

  • uninitialized_move([ExecPol,] ForwardIterator first, ForwardIterator last, ForwardIterator dest)
    uninitialized_copy 相同,但将 [first, last) 范围内的元素移动到原始内存中。

  • uninitialized_move_n([ExecPol,] ForwardIterator first, size_t nObjects, ForwardIterator dest)
    与上述算法相同,但移动 nObjects 个元素。

  • uninitialized_value_construct([ExecPol,] ForwardIterator first, ForwardIterator last)
    uninitialized_default_construct 相似,但要求迭代器所指的类型定义了 value_type 返回其类型名称。

  • uninitialized_value_construct_n([ExecPol,] ForwardIterator first, size_t nObjects)
    与上述算法相同,但在未初始化的内存中安装 nObjects 个值。

  • Type *construct_at(Type *raw, Args &&...args)
    在原始内存 raw 处构造类型 Type 的对象,传递 args...Type 的构造函数。

删除未初始化内存中的对象
  • void destroy([ExecPol,] ForwardIterator first, ForwardIterator last)
    假设 first 指向的类型,它对 [first, last) 范围内的所有元素调用 iterator->~Type()

  • void destroy([ExecPol,] ForwardIterator first, size_t nObjects)
    与上述算法相同,但调用 nObjects 个对象的析构函数。

  • void destroy_at(Type *raw)
    调用原始内存 raw 处对象的析构函数。如果 raw 指向一个由 placement new 分配的对象数组,则调用数组中每个元素的析构函数。

示例代码
#include <memory>
#include <vector>
#include <iostream>
#include <string>

using namespace std;

int main() {
    char raw[4 * sizeof(string)]; // 用于接收字符串的原始内存
    string *ptr = reinterpret_cast<string *>(raw); // 指向字符串的指针

    // 在原始内存中构造 4 个字符串
    uninitialized_default_construct_n(ptr, 4);
    destroy(ptr, ptr + 4); // 调用字符串的析构函数

    vector<string> vs(4, "string"); // 移动 4 个字符串到原始内存
    uninitialized_move(vs.begin(), vs.end(), ptr);

    cout << vs.front() << ", " << vs.back() << '\n';
    cout << ptr[0] << ", " << ptr[3] << '\n';

    destroy(ptr, ptr + 4); // 调用字符串的析构函数
}
输出
string, string
string, string
说明
  • uninitialized_copyuninitialized_move 等算法可以在未初始化的内存中进行对象的拷贝或移动,避免了直接操作原始内存时的复杂性。
  • destroydestroy_at 函数用于显式调用对象的析构函数,确保正确清理已构造对象的资源。

unique

在这里插入图片描述

头文件
  • <algorithm>
函数原型
  • ForwardIterator unique([ExecPol,] ForwardIterator first, ForwardIterator last);
    使用数据类型的 operator==,将 [first, last) 范围内的所有连续相等元素中的除了第一个之外的其他元素移到范围的末尾。返回的前向迭代器标记了剩余元素的开始。所有 [first, return-value) 范围内的元素都是唯一的,所有 [return-value, last) 范围内的元素具有不确定(但有效)的值。

  • ForwardIterator unique([ExecPol,] ForwardIterator first, ForwardIterator last, BinaryPredicate pred);
    使用二元谓词 pred,将 [first, last) 范围内的所有连续元素中,谓词 pred 返回 true 的元素(除了第一个)移到范围的末尾。谓词 pred 期望两个参数,这两个参数是迭代器指向的数据类型。返回的前向迭代器标记了剩余元素的开始。在 [first, return-value) 范围内的所有元素使 pred 返回 false(即它们是唯一的)。所有剩余的元素(即 [return-value, last) 范围内的元素)具有不确定(但有效)的值。

  • OutputIterator unique_copy([ExecPol,] InputIterator first, InputIterator last, OutputIterator result);
    [first, last) 范围内的唯一元素复制到从 result 开始的输出范围中。返回的输出迭代器标记了超出最后一个复制元素的位置。

  • OutputIterator unique_copy([ExecPol,] InputIterator first, InputIterator last, OutputIterator result, BinaryPredicate pred);
    使用二元谓词 pred,将 [first, last) 范围内的唯一元素(谓词 pred 返回 false 的元素)复制到从 result 开始的输出范围中。返回的输出迭代器标记了超出最后一个复制元素的位置。

描述

std::unique 通用算法假设范围内的元素已经排序(参见第19.1.54节)。

  • 第一个原型:使用数据类型的 operator==,将 [first, last) 范围内的连续相等元素中的第一个之外的其他元素移到范围的末尾。返回的前向迭代器标记了剩余元素的开始。 [first, return-value) 范围内的所有元素都是唯一的,而 [return-value, last) 范围内的元素具有不确定(但有效)的值。

  • 第二个原型:使用二元谓词 pred,将 [first, last) 范围内的连续元素中,谓词 pred 返回 true 的元素(除了第一个)移到范围的末尾。返回的前向迭代器标记了剩余元素的开始。在 [first, return-value) 范围内的所有元素使 pred 返回 false(即它们是唯一的)。所有剩余的元素(即 [return-value, last) 范围内的元素)具有不确定(但有效)的值。

示例代码
#include <algorithm>
#include <cstring>
#include <iostream>
#include <iterator>
#include <string>

using namespace std;

bool casestring(string const &first, string const &second) {
    return strcasecmp(first.c_str(), second.c_str()) == 0;
}

int main() {
    string words[] = {"alpha", "alpha", "Alpha", "papa", "quebec"};
    size_t const size = sizeof(words) / sizeof(string);
    
    string *removed = unique(words, words + size);
    copy(words, removed, ostream_iterator<string>(cout, " "));
    cout << '\n' << "Trailing elements are:\n";
    copy(removed, words + size, ostream_iterator<string>(cout, " "));
    cout << '\n';

    removed = unique(words, words + size, casestring);
    copy(words, removed, ostream_iterator<string>(cout, " "));
    cout << '\n' << "Trailing elements are:\n";
    copy(removed, words + size, ostream_iterator<string>(cout, " "));
    cout << '\n';
}
输出
alpha Alpha papa quebec
Trailing elements are:
quebec

alpha papa quebec
Trailing elements are:
quebec quebec
说明
  • unique:用于删除范围内的重复元素,只保留每个重复序列的第一个元素。可以使用默认的 == 比较,也可以提供自定义的二元谓词进行比较。
  • unique_copy:与 unique 类似,但不会在原始范围内修改元素,而是将唯一的元素复制到另一个范围中。

unique_copy

在这里插入图片描述

头文件
  • <algorithm>
函数原型
  • OutputIterator unique_copy([ExecPol,] InputIterator first, InputIterator last, OutputIterator result);
    [first, last) 范围内的元素复制到从 result 开始的目标容器中。连续相等的元素(使用数据类型的 operator==)仅复制一次(保留重复序列中的第一个元素)。返回的输出迭代器指向最后一个复制元素的下一个位置。

  • OutputIterator unique_copy([ExecPol,] InputIterator first, InputIterator last, OutputIterator result, BinaryPredicate pred);
    [first, last) 范围内的元素复制到从 result 开始的目标容器中。连续的元素中,谓词 pred 返回 true 的元素仅复制一次(保留重复序列中的第一个元素)。返回的输出迭代器指向最后一个复制元素的下一个位置。

描述
  • 第一个原型:将 [first, last) 范围内的元素复制到目标容器中,从 result 开始。连续相等的元素(使用数据类型的 operator==)仅复制一次(保留连续相等元素中的第一个)。返回的输出迭代器指向最后一个复制元素的下一个位置。

  • 第二个原型:将 [first, last) 范围内的元素复制到目标容器中,从 result 开始。连续的元素中,对于谓词 pred 返回 true 的元素仅复制一次(保留连续相等元素中的第一个)。返回的输出迭代器指向最后一个复制元素的下一个位置。

示例代码
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <cstring>

using namespace std;

bool casestring(string const &first, string const &second) {
    return strcasecmp(first.c_str(), second.c_str()) == 0;
}

int main() {
    string words[] = {"oscar", "Alpha", "alpha", "alpha", "papa", "quebec"};
    size_t const size = sizeof(words) / sizeof(string);

    vector<string> remaining;
    unique_copy(words, words + size, back_inserter(remaining));
    copy(remaining.begin(), remaining.end(), ostream_iterator<string>(cout, " "));
    cout << '\n';

    vector<string> remaining2;
    unique_copy(words, words + size, back_inserter(remaining2), casestring);
    copy(remaining2.begin(), remaining2.end(), ostream_iterator<string>(cout, " "));
    cout << '\n';
}
输出
oscar Alpha alpha papa quebec
oscar Alpha papa quebec
说明
  • unique_copy:用于将范围内的唯一元素复制到另一个容器中。相邻相等的元素(默认使用 == 比较)只复制第一个。可以通过提供自定义的二元谓词来控制相等元素的比较。

upper_bound

在这里插入图片描述

头文件
  • <algorithm>
函数原型
  • ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last, Type const &value);
    [first, last) 范围内的有序元素(按升序排序)中,搜索第一个大于 value 的元素。返回的迭代器指向可以插入 value 的位置,而不会破坏元素的有序性。若没有找到这样的元素,则返回 last

  • ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last, Type const &value, Compare comp);
    [first, last) 范围内的元素必须按 comp 函数或函数对象排序。comp 函数用于将每个元素与 value 进行比较。返回的迭代器指向第一个 comp 函数应用于元素和 value 返回 true 的位置。注意:与 lower_bound 不同,comp 函数的参数顺序在 upper_bound 中与 lower_bound 相反。

描述
  • 第一个原型:用于按升序排序的元素范围。返回的迭代器指向第一个大于 value 的位置。如果没有找到这样的元素,则返回 last

  • 第二个原型:用于按 comp 函数排序的元素范围。返回的迭代器指向第一个 comp 函数返回 true 的位置。如果没有找到这样的元素,则返回 last

示例代码
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <cstring>

using namespace std;

int main() {
    using pic = pair<int, char>;

    pic picArr[] = {{1, 'f'}, {5, 'r'}, {5, 'a'}, {7, 'n'}, {8, 'k'}};
    pic *picArrEnd = picArr + size(picArr);

    cout << "Sequence: ";
    for (auto &pair : picArr) 
        cout << '{' << pair.first << ',' << pair.second << "}, ";
    cout << '\n';

    // 使用自定义比较函数查找 lower_bound 和 upper_bound
    auto iter = lower_bound(picArr, picArrEnd, 5,
        [&](pic const &range, int value) {
            return range.first < value;
        });
    cout << "lower_bound, <, {5,?} can be inserted before {" << iter->first << ',' << iter->second << "}\n";

    iter = upper_bound(picArr, picArrEnd, 5,
        [&](int value, pic const &range) {
            return value < range.first;
        });
    cout << "upper_bound, <, {5,?} can be inserted before {" << iter->first << ',' << iter->second << "}\n";

    iter = upper_bound(picArr, picArrEnd, 9,
        [&](int value, pic const &range) {
            return value < range.first;
        });
    cout << "upper_bound, <, {9,?} can be inserted " 
         << (&*iter == picArrEnd ? "at the end" : "???") << '\n';

    // 按降序排序后再次使用 lower_bound 和 upper_bound
    sort(picArr, picArrEnd,
        [](pic const &lhs, pic const &rhs) {
            return lhs.first > rhs.first;
        });

    cout << "\nSequence: ";
    for (auto &pair: picArr)
        cout << '{' << pair.first << ',' << pair.second << "}, ";
    cout << '\n';

    iter = lower_bound(picArr, picArrEnd, 5,
        [&](pic const &range, int value) {
            return range.first > value;
        });
    cout << "lower_bound, >, {5,?} can be inserted before {" << iter->first << ',' << iter->second << "}\n";

    iter = upper_bound(picArr, picArrEnd, 5,
        [&](int value, pic const &range) {
            return value > range.first;
        });
    cout << "upper_bound, >, {5,?} can be inserted before {" << iter->first << ',' << iter->second << "}\n";

    iter = upper_bound(picArr, picArrEnd, 0,
        [&](int value, pic const &range) {
            return value > range.first;
        });
    cout << "upper_bound, >, {0,?} can be inserted " 
         << (&*iter == picArrEnd ? "at the end" : "???") << '\n';
}
输出
Sequence: {1,f}, {5,r}, {5,a}, {7,n}, {8,k}, 
lower_bound, <, {5,?} can be inserted before {5,r}
upper_bound, <, {5,?} can be inserted before {7,n}
upper_bound, <, {9,?} can be inserted at the end

Sequence: {8,k}, {7,n}, {5,r}, {5,a}, {1,f}, 
lower_bound, >, {5,?} can be inserted before {5,r}
upper_bound, >, {5,?} can be inserted before {1,f}
upper_bound, >, {0,?} can be inserted at the end
说明
  • 第 7 行到第 12 行picArr 数组中的元素按其第一个成员进行排序。
  • 第 18 行到第 23 行:使用自定义比较函数调用 lower_bound。注意第 19 行中,lambda 表达式的第一个参数是范围内的值,而第二个参数是目标值。
  • 第 27 行到第 32 行:使用自定义比较函数调用 upper_bound。与 lower_bound 不同,lambda 表达式的第一个参数是目标值,而第二个参数是范围内的值。
  • 第 57 行到第 80 行:对 picArr 数组进行降序排序后,使用 lower_boundupper_bound。此时应使用 > 运算符代替 < 运算符。

堆算法

堆是一种可以用数组表示的二叉树。在标准堆中,元素的键值不小于其子节点的键值。这种堆称为最大堆(max heap)。如图 19.1 所示,包含键值的树可以按照以下方式组织。这样的树也可以组织成数组形式:
在这里插入图片描述

12, 11, 10, 8, 9, 7, 6, 1, 2, 4, 3, 5

在以下描述中,请记住两个指针:一个指向树的下一个节点,另一个指向下一个节点的子节点。最初,node 指向第一个元素,child 指向第二个元素。

  • ∗node++ (== 12):12 是根节点,它的子节点是 ∗child++ (11)∗child++ (10),都小于 12。
  • 下一个节点 ∗node++ (== 11):它的子节点是 ∗child++ (8)∗child++ (9)
  • 下一个节点 ∗node++ (== 10):它的子节点是 ∗child++ (7)∗child++ (6)
  • 下一个节点 ∗node++ (== 8):它的子节点是 ∗child++ (1)∗child++ (2)
  • 节点 ∗node++ (== 9):它的子节点是 ∗child++ (4)∗child++ (3)
  • 最后(考虑到子节点)∗node++ (== 7) 只有一个子节点 ∗child++ (5)。由于 child 现在指向数组之外,剩余的节点没有子节点。因此,节点 6、1、2、4、3 和 5 没有子节点。

注意,左支和右支的顺序并不一致:8 小于 9,但 7 大于 6。

堆是通过逐层遍历二叉树来创建的,从顶节点开始。顶节点是 12,位于第零层。在第一层我们找到 11 和 10。在第二层找到 8、9、7 和 6,依此类推。

堆可以在支持随机访问的容器中构建。因此,列表不适合作为堆的数据结构。堆可以从一个(未排序的)数组中构建(使用 make_heap)。可以从堆中删除顶元素,然后重新排序堆(使用 pop_heap),可以向堆中添加新元素,然后重新排序堆(使用 push_heap),还可以对堆中的元素进行排序(使用 sort_heap,这会使堆失效)。

make_heap 函数

  • 头文件: <algorithm>

  • 函数原型:

    • void make_heap(RandomAccessIterator first, RandomAccessIterator last);
    • void make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
  • 描述:

    • 第一个原型: 将范围 [first, last) 中的元素重新排序,形成一个最大堆(max-heap),使用数据类型的 operator< 进行比较。
    • 第二个原型: 将范围 [first, last) 中的元素重新排序,形成一个最大堆(max-heap),使用二进制比较函数对象 comp 进行比较。

push_heap 函数

  • 头文件: <algorithm>

  • 函数原型:

    • void push_heap(RandomAccessIterator first, RandomAccessIterator last);
    • void push_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
  • 描述:

    • 第一个原型: 假设范围 [first, last - 1) 已经包含一个有效的堆,并且 last - 1 位置的元素是要添加到堆中的新元素,则将范围 [first, last - 1) 中的元素重新排序,形成一个最大堆(max-heap),使用数据类型的 operator< 进行比较。
    • 第二个原型: 假设范围 [first, last - 1) 已经包含一个有效的堆,并且 last - 1 位置的元素是要添加到堆中的新元素,则将范围 [first, last - 1) 中的元素重新排序,形成一个最大堆(max-heap),使用二进制比较函数对象 comp 进行比较。

sort_heap 函数

  • 头文件: <algorithm>

  • 函数原型:

    • void sort_heap(RandomAccessIterator first, RandomAccessIterator last);
    • void sort_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
  • 描述:

    • 第一个原型: 假设范围 [first, last) 中的元素构成一个有效的最大堆(max-heap),则将范围 [first, last) 中的元素进行排序,使用数据类型的 operator< 进行比较。
    • 第二个原型: 假设范围 [first, last) 中的元素构成一个有效的堆,则将范围 [first, last) 中的元素进行排序,使用二进制比较函数对象 comp 进行比较。

使用堆函数的示例

以下是一个示例,展示了如何使用各种堆操作算法:

#include <algorithm>
#include <iostream>
#include <functional>
#include <iterator>
using namespace std;

void show(int *ia, char const *header){
    cout << header << ":\n";
    copy(ia, ia + 20, ostream_iterator<int>(cout, " "));
    cout << '\n';
}

int main()
{
    int ia[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
                11, 12, 13, 14, 15, 16, 17, 18, 19, 20};

    // 将数组转化为最大堆
    make_heap(ia, ia + 20);
    show(ia, "The values 1-20 in a max-heap");

    // 从堆中移除第一个元素(现在在末尾)
    pop_heap(ia, ia + 20);
    show(ia, "Removing the first element (now at the end)");

    // 将20(在末尾)重新加入堆
    push_heap(ia, ia + 20);
    show(ia, "Adding 20 (at the end) to the heap again");

    // 对堆中的元素进行排序
    sort_heap(ia, ia + 20);
    show(ia, "Sorting the elements in the heap");

    // 使用 greater<int> 重新构建堆
    make_heap(ia, ia + 20, greater<int>());
    show(ia, "The values 1-20 in a heap, using > (and beyond too)");

    // 从堆中移除第一个元素(现在在末尾)
    pop_heap(ia, ia + 20, greater<int>());
    show(ia, "Removing the first element (now at the end)");

    // 重新将被移除的元素加入堆
    push_heap(ia, ia + 20, greater<int>());
    show(ia, "Re-adding the removed element");

    // 对堆中的元素进行排序
    sort_heap(ia, ia + 20, greater<int>());
    show(ia, "Sorting the elements in the heap");
}
显示的结果:
The values 1-20 in a max-heap:
20 19 15 18 11 13 14 17 9 10 2 12 6 3 7 16 8 4 1 5

Removing the first element (now at the end):
19 18 15 17 11 13 14 16 9 10 2 12 6 3 7 5 8 4 1 20

Adding 20 (at the end) to the heap again:
20 19 15 17 18 13 14 16 9 11 2 12 6 3 7 5 8 4 1 10

Sorting the elements in the heap:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

The values 1-20 in a heap, using > (and beyond too):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Removing the first element (now at the end):
2 4 3 8 5 6 7 16 9 10 11 12 13 14 15 20 17 18 19 1

Re-adding the removed element:
1 2 3 8 4 6 7 16 9 5 11 12 13 14 15 20 17 18 19 10

Sorting the elements in the heap:
20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值