C++11 STL常用算法

C++11 STL常用算法

34

清平乐·六盘山

天高云淡,望断南飞雁。不到长城非好汉,屈指行程二万。
六盘山上高峰,红旗漫卷西风。今日长缨在手,何时缚住苍龙?


1. 非修改序列操作

1.1 批处理操作

1.1.1 for_each

函数对象,将应用于[first, last) 中每个迭代器解引用后的结果 函数的签名应等效于以下内容 void fun(const Type &a);签名不需要有 const &。 类型 Type 必须是使得类型为 InputIt 的对象可以被解引用,然后隐式转换为 Type。

template< class InputIt, class UnaryFunc >
UnaryFunc for_each( InputIt first, InputIt last, UnaryFunc f );

伪码实现

template<class InputIt, class UnaryFunc> 
constexpr UnaryFunc for_each(InputIt first, InputIt last, UnaryFunc f) 
{    
    for (; first != last; ++first)        
        f(*first);     
    return f;
}

测试案例:

    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';
    
    /// 输出结果
    before:	3 -4 2 -8 15 267 
	after:	4 -3 3 -7 16 268 

1.2 搜索操作

1.2.1 all_of | any_of | none_of

template< class InputIt, class UnaryFunc >
// 1. 检查一元谓词 p 对于范围 [first, last) 中至少一个元素是否返回 false
bool all_of( InputIt first, InputIt last, UnaryPred p );
// 2. 检查一元谓词 p 对于范围 [first, last) 中至少一个元素是否返回 true
bool any_of( InputIt first, InputIt last, UnaryPred p );
// 3. 检查一元谓词 p 对于范围 [first, last) 中所有元素是否均不返回 true
bool none_of( InputIt first, InputIt last, UnaryPred p );

伪码实现

template<class InputIt, class UnaryPred>
constexpr bool all_of(InputIt first, InputIt last, UnaryPred p)
{
    return std::find_if_not(first, last, p) == last;
}

template<class InputIt, class UnaryPred>
constexpr bool any_of(InputIt first, InputIt last, UnaryPred p)
{
    return std::find_if(first, last, p) != last;
}

template<class InputIt, class UnaryPred>
constexpr bool none_of(InputIt first, InputIt last, UnaryPred p)
{
    return std::find_if(first, last, p) == last;
}

测试案例:

    std::vector<int> v(10, 2);
    std::partial_sum(v.cbegin(), v.cend(), v.begin());
    std::cout << "Among the numbers: ";
    std::copy(v.cbegin(), v.cend(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';

    if (std::all_of(v.cbegin(), v.cend(), [](int i) { return i % 2 == 0; }))
        std::cout << "All numbers are even\n";

    if (std::none_of(v.cbegin(), v.cend(), std::bind(std::modulus<>(),
                                                     std::placeholders::_1, 2)))
        std::cout << "None of them are odd\n";

    struct DivisibleBy
    {
        const int d;
        DivisibleBy(int n) : d(n) {}
        bool operator()(int n) const { return n % d == 0; }
    };

    if (std::any_of(v.cbegin(), v.cend(), DivisibleBy(7)))
        std::cout << "At least one number is divisible by 7\n";
    
    /// 输出结果
    Among the numbers: 2 4 6 8 10 12 14 16 18 20 
    All numbers are even
    None of them are odd
    At least one number is divisible by 7

1.2.2 find | find_if | find_if_not

寻找第一个满足特定条件的元素

template< class InputIt, class UnaryFunc >
// 1. find 搜索等于 value 的元素(使用 operator==)。
InputIt find( InputIt first, InputIt last, const T& value );
// 2. find_if 搜索谓词 p 返回 true 的元素。
InputIt find_if( InputIt first, InputIt last, UnaryPred p );
// 3. find_if_not 搜索谓词 q 返回 false 的元素。
InputIt find_if_not( InputIt first, InputIt last, UnaryPred q );

伪码实现

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;
}

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;
}

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;
}

测试案例:

    const auto haystack = {1, 2, 3, 4};
    for (const int needle : {3, 5})
        if (std::find(haystack.begin(), haystack.end(), needle) == haystack.end())
            std::cout << "haystack does not contain " << needle << '\n';
        else
            std::cout << "haystack contains " << needle << '\n';


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

	/// 输出结果
    haystack contains 3
    haystack does not contain 5
    haystack contains an even number 4
    haystack does not contain even numbers

1.2.3 count | count_if

返回满足特定条件的元素数量

template< class InputIt, class UnaryFunc >
// 1. find 搜索等于 value 的元素(使用 operator==)。
typename std::iterator_traits<InputIt>::difference_type
    count( InputIt first, InputIt last, const T& value );

// 2. find_if 搜索谓词 p 返回 true 的元素。
typename std::iterator_traits<InputIt>::difference_type
    count_if( InputIt first, InputIt last, UnaryPred p );

伪码实现

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;
}

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;
}

测试案例:

    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';

    // Determine how many integers match a target value.
    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';
    }

    // Use a lambda expression to count elements divisible by 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';


	/// 输出结果
    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

1.2.4 search | search_if

搜索一个范围的元素首次出现的位置。

指向范围 [first, last) 中序列 [s_first, s_last) 第一次出现的起始位置的迭代器。如果没有找到这样的出现,则返回 last。

template< class InputIt, class UnaryFunc >
ForwardIt1 search( ForwardIt1 first, ForwardIt1 last,
                   ForwardIt2 s_first, ForwardIt2 s_last );

伪码实现

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;
    }
}

测试案例:

    std::vector<int> vec1 = {1, 2, 3, 4};
    std::vector<int> v2 = {2, 3};
    std::vector<int> v = {1, 4};

    auto iter = std::search(vec1.cbegin(), vec1.cend(), v.cbegin(), v.cend());
    // 检查是否找到
    if (iter != vec1.cend()) {
        std::cout << "Found at position: " << std::distance(vec1.cbegin(), iter) << std::endl;
    } else {
        std::cout << "Not found!" << std::endl;
    }


	/// 输出结果
	Not found!

1.2.5 adjacent_find

寻找第一对相等的(或满足给定谓词的)相邻项

在范围 [first, last) 中搜索两个连续相等的元素。

template< class InputIt, class UnaryFunc >
ForwardIt adjacent_find( ForwardIt first, ForwardIt last );

伪码实现

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;
}

测试案例:

    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';

	/// 输出结果
    The first adjacent pair of equal elements is at 4, *i1 = 40

1.2.6 find_first_if

用于在第一个范围中查找第二个范围中任意一个元素首次出现位置

template< class InputIt, class UnaryFunc >
InputIt find_first_of( InputIt first, InputIt last,
                       ForwardIt s_first, ForwardIt s_last );

伪码实现

template<class InputIt, class ForwardIt>
InputIt find_first_of(InputIt first, InputIt last,
                      ForwardIt s_first, ForwardIt s_last)
{
    for (; first != last; ++first)
        for (ForwardIt it = s_first; it != s_last; ++it)
            if (*first == *it)
                return first;
    return last;
}

测试案例:

    std::vector<int> data = {1, 2, 3, 4, 5, 6};
    std::vector<int> search_for = {3, 5, 7};
    
    // 在data中查找search_for中的任意一个数字
    auto it = std::find_first_of(data.begin(), data.end(),
                                 search_for.begin(), search_for.end());
    
    if (it != data.end()) {
        std::cout << "Found " << *it << " at position " 
                  << std::distance(data.begin(), it) << std::endl;
        // 输出: Found 3 at position 2
    } else {
        std::cout << "Not found" << std::endl;
    }

2 修改序列操作

2.1 复制操作

2.1.1 copy | copy_if

将源范围内的元素复制到目标位置。

template< class InputIt, class UnaryFunc >
OutputIt copy( InputIt first, InputIt last,
               OutputIt d_first );

template< class InputIt, class OutputIt, class UnaryPred >
OutputIt copy_if( InputIt first, InputIt last,
                  OutputIt d_first, UnaryPred pred );

伪码实现

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;
}

template<class InputIt, class OutputIt, class UnaryPred>
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;
}

测试案例:

    std::vector<int> source = {1, 2, 3, 4, 5};
    std::vector<int> destination(5); // 需要预分配空间

    // 复制整个范围
    std::copy(source.begin(), source.end(), destination.begin());

    // 输出结果:1 2 3 4 5
    for (int num : destination) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    std::vector<int> src = {10, 20, 30, 40, 50};
    std::vector<int> dst(3);
    std::copy(src.begin() + 1, src.begin() + 4, dst.begin());
    // dst: {20, 30, 40}

2.2 转换操作

这两个算法用于替换容器中满足条件的元素。

2.2.1 replace| replace_if

将源范围内的元素复制到目标位置。

template< class ForwardIt, class T >
void replace( ForwardIt first, ForwardIt last,
              const T& old_value, const T& new_value );

template< class ForwardIt, class UnaryPred,
          class T = typename std::iterator_traits
                        <ForwardIt>::value_type> >
constexpr void replace_if( ForwardIt first, ForwardIt last,
                           UnaryPred p, const T& new_value );

伪码实现

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;
}

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;
}

测试案例:

    std::vector<int> numbers = {1, 2, 3, 2, 4, 2, 5};
    // 将所有值为 2 的元素替换为 99
    std::replace(numbers.begin(), numbers.end(), 2, 99);

	// 将所有偶数替换为 0
    std::replace_if(numbers.begin(), numbers.end(),
                    [](int x) { return x % 2 == 0; }, 0);

2.3 生成操作

2.3.1 fill | fill_n

将给定值复制赋给一个范围中的每个元素

template< class ForwardIt, class T >
void fill( ForwardIt first, ForwardIt last, const T& value );

template< class OutputIt, class Size, class T >
OutputIt fill_n( OutputIt first, Size count, const T& value );

伪码实现

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;
}

template<class OutputIt, class Size,
         class T = typename std::iterator_traits<OutputIt>::value_type>
OutputIt fill_n(OutputIt first, Size count, const T& value)
{
    for (Size i = 0; i < count; i++)
        *first++ = value;
    return first;
}

测试案例:

    std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8};
    println(v);
 
    // set all of the elements to 8
    std::fill(v.begin(), v.end(), 8);
    println(v);

    std::vector<int> v1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    // replace values of the first 5 elements with -1
    std::fill_n(v1.begin(), 5, -1);

2.3.2 generate

将连续函数调用的结果赋给一个范围中的每个元素

template< class ForwardIt, class Generator >
void generate( ForwardIt first, ForwardIt last, Generator g );

伪码实现

template<class ForwardIt, class Generator>
constexpr //< since C++20
void generate(ForwardIt first, ForwardIt last, Generator g)
{
    for (; first != last; ++first)
        *first = g();
}

测试案例:

int f()
{
    static int i;
    return ++i;
}
 
int main()
{
    std::vector<int> v(5);
 
    std::generate(v.begin(), v.end(), f);
    println("v: ", v);
 
    // Initialize with default values 0,1,2,3,4 from a lambda function
    // Equivalent to std::iota(v.begin(), v.end(), 0);
    std::generate(v.begin(), v.end(), [n = 0] () mutable { return n++; });
    println("v: ", v);
    
    v: 1 2 3 4 5
	v: 0 1 2 3 4
}

2.4 移除操作

2.4.1 remove | remove_if

这两个算法用于"移除"容器中满足条件的元素,但不会真正删除元素,而是将不需要移除的元素移动到容器前面,返回新的逻辑结尾。

template< class ForwardIt, class T >
ForwardIt remove( ForwardIt first, ForwardIt last, const T& value );

template< class ForwardIt, class UnaryPred >
ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPred p );

伪码实现

template<class ForwardIt, class T = typename std::iterator_traits<ForwardIt>::value_type>
ForwardIt remove(ForwardIt first, ForwardIt last, const T& value)
{
    first = std::find(first, last, value);
    if (first != last)
        for (ForwardIt i = first; ++i != last;)
            if (!(*i == value))
                *first++ = std::move(*i);
    return first;
}

template<class ForwardIt, class UnaryPred>
ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPred p)
{
    first = std::find_if(first, last, p);
    if (first != last)
        for (ForwardIt i = first; ++i != last;)
            if (!p(*i))
                *first++ = std::move(*i);
    return first;
}

测试案例:

int main()
{
    std::vector<int> numbers = {1, 2, 3, 2, 4, 2, 5, 2};

    std::cout << "原始数据: ";
    for (int n : numbers) std::cout << n << " ";
    std::cout << std::endl;

    // 移除所有值为2的元素
    auto new_end = std::remove(numbers.begin(), numbers.end(), 2);

    std::cout << "remove后(容器实际内容): ";
    for (int n : numbers) std::cout << n << " ";
    std::cout << std::endl;

    std::cout << "逻辑有效范围: ";
    for (auto it = numbers.begin(); it != new_end; ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    // 真正删除
    numbers.erase(new_end, numbers.end());

    std::cout << "erase后: ";
    for (int n : numbers) std::cout << n << " ";
    std::cout << std::endl;
    std::cout << "容器大小: " << numbers.size() << std::endl;
    
    // 输出
    原始数据: 1 2 3 2 4 2 5 2 
    remove后(容器实际内容): 1 3 4 5 4 2 5 2 
    逻辑有效范围: 1 3 4 5 
    erase后: 1 3 4 5 
    容器大小: 4
}

2.4.2 unique

移除一个范围中的连续重复元素

template< class ForwardIt >
ForwardIt unique( ForwardIt first, ForwardIt last );

伪码实现

template<class ForwardIt>
ForwardIt unique(ForwardIt first, ForwardIt last)
{
    if (first == last)
        return last;
 
    ForwardIt result = first;
    while (++first != last)
        if (!(*result == *first) && ++result != first)
            *result = std::move(*first);
 
    return ++result;
}

测试案例:

int f()
{
    static int i;
    return ++i;
}
 
int main()
{
std::vector<int> numbers = {1, 2, 2, 3, 3, 3, 4, 5, 5, 5, 5, 6};
    
    std::cout << "原始数据: ";
    for (int n : numbers) std::cout << n << " ";
    std::cout << std::endl;
    
    // 先排序
    std::sort(numbers.begin(), numbers.end());
    std::cout << "排序后:   ";
    for (int n : numbers) std::cout << n << " ";
    std::cout << std::endl;
    
    // 使用 unique 移除相邻重复元素
    auto new_end = std::unique(numbers.begin(), numbers.end());
    
    std::cout << "unique后: ";
    for (int n : numbers) std::cout << n << " ";
    std::cout << std::endl;
    
    std::cout << "有效范围: ";
    for (auto it = numbers.begin(); it != new_end; ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    
    // 真正删除重复元素
    numbers.erase(new_end, numbers.end());
    
    std::cout << "最终结果: ";
    for (int n : numbers) std::cout << n << " ";
    std::cout << std::endl;
    
    原始数据: 1 2 2 3 3 3 4 5 5 5 5 6 
    排序后:   1 2 2 3 3 3 4 5 5 5 5 6 
    unique后: 1 2 3 4 5 6 3 4 5 5 5 6  // 后面是"垃圾"数据
    有效范围: 1 2 3 4 5 6 
    最终结果: 1 2 3 4 5 6 
}

2.5 改变顺序操作

2.5.1 reverse

反转一个范围中元素的顺序

template< class BidirIt >
void reverse( BidirIt first, BidirIt last );

伪码实现

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);
}

测试案例:

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);
    
    // 输出
    after reverse, v = 3 2 1
    after reverse, a = 7 6 5 4
}

2.5.2 shuffle

重新排列给定范围 [first, last) 中的元素,使得这些元素所有可能的排列都具有相同的出现概率。

template< class RandomIt >
void random_shuffle( RandomIt first, RandomIt last );

伪码实现

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.
    }
}

测试案例:

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';
    
    // 输出
	8 6 10 4 2 3 7 1 9 5
}

3. 排序操作

3.1 sort | stable_sort

重新排列给定范围 [first, last) 中的元素,使得这些元素所有可能的排列都具有相同的出现概率。

对一个范围的元素进行排序,同时保留相等元素之间的顺序(stable_sort).

template< class RandomIt >
void sort( RandomIt first, RandomIt last );

template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );

template< class RandomIt >
void stable_sort( RandomIt first, RandomIt last );

伪码实现


测试案例:

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");
    
    // 输出
    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
}

4 集合操作

4.1 includes

如果一个序列是另一个序列的子序列,则返回 true。

template< class InputIt1, class InputIt2 >
bool includes( InputIt1 first1, InputIt1 last1,
               InputIt2 first2, InputIt2 last2 );

template< class InputIt1, class InputIt2, class Compare >
bool includes( InputIt1 first1, InputIt1 last1,
               InputIt2 first2, InputIt2 last2, Compare comp );

伪码实现

template<class InputIt1, class InputIt2>
bool includes(InputIt1 first1, InputIt1 last1,
              InputIt2 first2, InputIt2 last2)
{
    for (; first2 != last2; ++first1)
    {
        if (first1 == last1 || *first2 < *first1)
            return false;
        if (!(*first1 < *first2))
            ++first2;
    }
    return true;
}

template<class InputIt1, class InputIt2, class Compare>
bool includes(InputIt1 first1, InputIt1 last1,
              InputIt2 first2, InputIt2 last2, Compare comp)
{
    for (; first2 != last2; ++first1)
    {
        if (first1 == last1 || comp(*first2, *first1))
            return false;
        if (!comp(*first1, *first2))
            ++first2;
    }
    return true;
}

测试案例:

int main()
{
    const auto
        v1 = {'a', 'b', 'c', 'f', 'h', 'x'},
        v2 = {'a', 'b', 'c'},
        v3 = {'a', 'c'},
        v4 = {'a', 'a', 'b'},
        v5 = {'g'},
        v6 = {'a', 'c', 'g'},
        v7 = {'A', 'B', 'C'};
 
    auto no_case = [](char a, char b) { return std::tolower(a) < std::tolower(b); };
 
    std::cout
    << v1 << "\nincludes:\n" << std::boolalpha
    << v2 << ": " << std::includes(v1.begin(), v1.end(), v2.begin(), v2.end()) << '\n'
    << v3 << ": " << std::includes(v1.begin(), v1.end(), v3.begin(), v3.end()) << '\n'
    << v4 << ": " << std::includes(v1.begin(), v1.end(), v4.begin(), v4.end()) << '\n'
    << v5 << ": " << std::includes(v1.begin(), v1.end(), v5.begin(), v5.end()) << '\n'
    << v6 << ": " << std::includes(v1.begin(), v1.end(), v6.begin(), v6.end()) << '\n'
    << v7 << ": " << std::includes(v1.begin(), v1.end(), v7.begin(), v7.end(), no_case)
          << " (case-insensitive)\n";
    
    // 输出
	a b c f h x
    includes:
    a b c   : true
    a c     : true
    a a b   : false
    g       : false
    a c g   : false
    A B C   : true (case-insensitive)
}

4.2 set_union

计算两个已经排序好的集合的并集

template< class InputIt1, class InputIt2, class OutputIt >
OutputIt set_union( InputIt1 first1, InputIt1 last1,
                    InputIt2 first2, InputIt2 last2,
                    OutputIt d_first );

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 );

伪码实现

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);
}

测试案例:

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 4 5 6 7 
	1 2 3 4 5 5 5 6 7
}

4.3 set_intersection

计算两个集合的交集。

构造一个始于 d_first 的有序范围,该范围由在两个有序范围 [first1, last1)[first2, last2) 中都存在的元素组成。

如果 [first1, last1) 包含 m 个彼此等价的元素,且 [first2, last2) 包含 n 个与它们等价的元素,则将前 std::min(m, n) 个元素从 [first1, last1) 复制到输出范围,并保留顺序。

template< class InputIt1, class InputIt2, class OutputIt >
OutputIt set_intersection( InputIt1 first1, InputIt1 last1,
                           InputIt2 first2, InputIt2 last2,
                           OutputIt d_first );

伪码实现

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;
}

测试案例:

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';
    
    // 输出
	5 7 7
}

4.4 set_difference

用于计算两个已排序集合的差集(A - B),计算在集合 A 中但不在集合 B 中的元素。

将已排序范围 [first1, last1) 中未在已排序范围 [first2, last2) 中找到的元素复制到始于 d_first 的范围。输出范围也已排序。

如果 [first1, last1) 包含 m 个彼此等价的元素,且 [first2, last2) 包含 n 个与它们等价的元素,则将 std::max(m - n, 0) 个元素从 [first1, last1) 复制到输出范围,并保持顺序。

template< class InputIt1, class InputIt2, class OutputIt >
OutputIt set_difference( InputIt1 first1, InputIt1 last1,
                         InputIt2 first2, InputIt2 last2,
                         OutputIt d_first );

伪码实现

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;
}

测试案例:

int main()
{
    std::vector<int> A = {1, 2, 3, 4, 5, 6, 7};
    std::vector<int> B = {2, 4, 6, 8, 10};
    std::vector<int> difference;
    
    // 确保输入已排序
    std::sort(A.begin(), A.end());
    std::sort(B.begin(), B.end());
    
    std::cout << "集合A: ";
    for (int n : A) std::cout << n << " ";
    std::cout << std::endl;
    
    std::cout << "集合B: ";
    for (int n : B) std::cout << n << " ";
    std::cout << std::endl;
    
    // 计算差集 A - B
    std::set_difference(A.begin(), A.end(),
                        B.begin(), B.end(),
                        std::back_inserter(difference));
    
    std::cout << "A - B (在A中但不在B中): ";
    for (int n : difference) std::cout << n << " ";
    std::cout << std::endl;
    
    // 输出
	集合A: 1 2 3 4 5 6 7 
    集合B: 2 4 6 8 10 
    A - B (在A中但不在B中): 1 3 5 7 
}

5 最值操作

5.1 max_element

返回一个范围中最大的元素

template< class ForwardIt >
ForwardIt max_element( ForwardIt first, ForwardIt last );

template< class ForwardIt, class Compare >
ForwardIt max_element( ForwardIt first, ForwardIt last,
                       Compare comp );

伪码实现

template<class ForwardIt>
ForwardIt max_element(ForwardIt first, ForwardIt last)
{
    if (first == last)
        return last;
 
    ForwardIt largest = first;
 
    while (++first != last)
        if (*largest < *first)
            largest = first;
 
    return largest;
}

template<class ForwardIt, class Compare>
ForwardIt max_element(ForwardIt first, ForwardIt last, Compare comp)
{
    if (first == last)
        return last;
 
    ForwardIt largest = first;
 
    while(++first != last)
        if (comp(*largest, *first))
            largest = first;
 
    return largest;
}

测试案例:

int main()
{
    std::vector<int> v{3, 1, -14, 1, 5, 9, -14, 9};
    std::vector<int>::iterator result;
 
    result = std::max_element(v.begin(), v.end());
    std::cout << "Max element found at index "
              << std::distance(v.begin(), result)
              << " has value " << *result << '\n';
 
    result = std::max_element(v.begin(), v.end(), [](int a, int b)
    {
        return std::abs(a) < std::abs(b);
    });
    std::cout << "Absolute max element found at index "
              << std::distance(v.begin(), result)
              << " has value " << *result << '\n';
    
    // 输出
    Max element found at index 5 has value 9
    Absolute max element found at index 2 has value -14
}

5.2 min_element

返回一个范围中最小的元素

重新排列给定范围 [first, last) 中的元素,使得这些元素所有可能的排列都具有相同的出现概率。

对一个范围的元素进行排序,同时保留相等元素之间的顺序(stable_sort).

template< class ForwardIt >
ForwardIt min_element( ForwardIt first, ForwardIt last );

template< class ForwardIt, class Compare >
ForwardIt min_element( ForwardIt first, ForwardIt last,
                       Compare comp );

伪码实现

template<class ForwardIt>
ForwardIt min_element(ForwardIt first, ForwardIt last)
{
    if (first == last)
        return last;
 
    ForwardIt smallest = first;
 
    while (++first != last)
        if (*first < *smallest)
            smallest = first;
 
    return smallest;
}

template<class ForwardIt, class Compare>
ForwardIt min_element(ForwardIt first, ForwardIt last, Compare comp)
{
    if (first == last)
        return last;
 
    ForwardIt smallest = first;
 
    while (++first != last)
        if (comp(*first, *smallest))
            smallest = first;
 
    return smallest;
}

测试案例:

int main()
{
    std::vector<int> v{3, 1, -4, 1, 5, 9};
 
    std::vector<int>::iterator result = std::min_element(v.begin(), v.end());
    std::cout << "min element has value " << *result << " and index ["
              << std::distance(v.begin(), result) << "]\n";
    
    // 输出
	min element has value -4 and index [2]
}

6 数值操作

6.1 accumulate

对一个范围的元素进行求和或折叠。

template< class InputIt, class T >
T accumulate( InputIt first, InputIt last, T init );

template< class InputIt, class T, class BinaryOp >
T accumulate( InputIt first, InputIt last, T init, BinaryOp op );

伪码实现

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;
}

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;
}

测试案例:

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]), // start with first element
                                    dash_fold);
 
    // Right fold using reverse iterators
    std::string rs = std::accumulate(std::next(v.rbegin()), v.rend(),
                                     std::to_string(v.back()), // start with last element
                                     dash_fold);
 
    std::cout << "sum: " << sum << '\n'
              << "product: " << product << '\n'
              << "dash-separated string: " << s << '\n'
              << "dash-separated string (right-folded): " << rs << '\n';
    
    // 输出
    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
}

7 排列操作(17)

7.1 is_permutation

确定一个序列是否是另一个序列的排列

对一个范围的元素进行求和或折叠。

template< class ForwardIt1, class ForwardIt2 >
bool is_permutation( ForwardIt1 first1, ForwardIt1 last1,
                     ForwardIt2 first2 );

template< class ForwardIt1, class ForwardIt2,
          class BinaryPredicate >
bool is_permutation( ForwardIt1 first1, ForwardIt1 last1,
                     ForwardIt2 first2, BinaryPredicate p );

伪码实现

template<class ForwardIt1, class ForwardIt2>
bool is_permutation(ForwardIt1 first, ForwardIt1 last,
                    ForwardIt2 d_first)
{
    // skip common prefix
    std::tie(first, d_first) = std::mismatch(first, last, d_first);
 
    // iterate over the rest, counting how many times each element
    // from [first, last) appears in [d_first, d_last)
    if (first != last)
    {
        ForwardIt2 d_last = std::next(d_first, std::distance(first, last));
        for (ForwardIt1 i = first; i != last; ++i)
        {
            if (i != std::find(first, i, *i))
                continue; // this *i has been checked
 
            auto m = std::count(d_first, d_last, *i);
            if (m == 0 || std::count(i, last, *i) != m)
                return false;
        }
    }
    return true;
}

测试案例:

int main()
{
    static constexpr auto v1 = {1, 2, 3, 4, 5};
    static constexpr auto v2 = {3, 5, 4, 1, 2};
    static constexpr auto v3 = {3, 5, 4, 1, 1};
 
    std::cout << v2 << " is a permutation of " << v1 << ": " << std::boolalpha
              << std::is_permutation(v1.begin(), v1.end(), v2.begin()) << '\n'
              << v3 << " is a permutation of " << v1 << ": "
              << std::is_permutation(v1.begin(), v1.end(), v3.begin()) << '\n';
    
    // 输出
    { 3 5 4 1 2 } is a permutation of { 1 2 3 4 5 }: true
    { 3 5 4 1 1 } is a permutation of { 1 2 3 4 5 }: false
}

7.2 next_permutation

生成元素范围的下一个更大的字典序排列

template< class BidirIt >
bool next_permutation( BidirIt first, BidirIt last );

伪码实现

template<class BidirIt>
bool next_permutation(BidirIt first, BidirIt last)
{
    auto r_first = std::make_reverse_iterator(last);
    auto r_last = std::make_reverse_iterator(first);
    auto left = std::is_sorted_until(r_first, r_last);
 
    if (left != r_last)
    {
        auto right = std::upper_bound(r_first, left, *left);
        std::iter_swap(left, right);
    }
 
    std::reverse(left.base(), last);
    return left != r_last;
}

测试案例:

int main()
{
    std::string s = "aba";
 
    do
    {
        std::cout << s << '\n';
    }
    while (std::next_permutation(s.begin(), s.end()));
 
    std::cout << s << '\n';
    
    // 输出
    aba
    baa
    aab
}

7.3 sample

用于从序列中随机抽取样本,支持有放回和无放回抽样。

template< class PopulationIt, class SampleIt, class Distance, class URBG >
SampleIterator sample( PopulationIt first, PopulationIt last,
                       SampleIt out, Distance n, URBG&& g );

伪码实现


测试案例:

int main()
{
    std::string in {"ABCDEFGHIJK"}, out;
    std::sample(in.begin(), in.end(), std::back_inserter(out), 4,
                std::mt19937 {std::random_device{}()});
    std::cout << "Four random letters out of " << in << " : " << out << '\n';
    
    // 输出
	Four random letters out of ABCDEFGHIJK: EFGK
}
posted on 2026-01-03 22:06  Hakuon  阅读(4)  评论(0)    收藏  举报