命名空间
变体
操作

std::ranges::partition

来自 cppreference.com
< cpp‎ | algorithm‎ | ranges
 
 
算法库
受限算法和范围上的算法 (C++20)
受限算法,例如 ranges::copy, ranges::sort, ...
执行策略 (C++17)
排序和相关操作
分区操作
排序操作
二分查找操作
(在分区范围上)
集合操作(在排序范围上)
合并操作(在排序范围上)
堆操作
最小值/最大值操作
(C++11)
(C++17)
字典序比较操作
排列操作
C 库
数值操作
未初始化内存操作
 
受限算法
此菜单中的所有名称都属于命名空间 std::ranges
非修改序列操作
修改序列操作
分区操作
排序操作
二分查找操作(在排序范围上)
       
       
集合操作(在排序范围上)
堆操作
最小值/最大值操作
       
       
排列操作
折叠操作
数值操作
(C++23)            
未初始化存储操作
返回类型
 
在头文件 <algorithm> 中定义
调用签名
template< std::permutable I, std::sentinel_for<I> S, class Proj = std::identity,

          std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
constexpr ranges::subrange<I>

    partition( I first, S last, Pred pred, Proj proj = {} );
(1) (自 C++20 起)
template< ranges::forward_range R, class Proj = std::identity,

          std::indirect_unary_predicate<
              std::projected<ranges::iterator_t<R>, Proj>> Pred >
requires std::permutable<ranges::iterator_t<R>>
constexpr ranges::borrowed_subrange_t<R>

    partition( R&& r, Pred pred, Proj proj = {} );
(2) (自 C++20 起)
1) 以这样的方式重新排序范围 [firstlast) 中的元素,使谓词 pred 返回 true 的所有元素的投影 proj 位于谓词 pred 返回 false 的元素的投影 proj 之前。元素的相对顺序不会被保留。
2)(1) 相同,但使用 r 作为源范围,就好像使用 ranges::begin(r) 作为 firstranges::end(r) 作为 last

此页面上描述的类似函数的实体是 *niebloids*,即

在实践中,它们可以实现为函数对象,或使用特殊的编译器扩展。

内容

[edit] 参数

first, last - 要重新排序的元素范围
r - 要重新排序的元素范围
pred - 要应用于投影元素的谓词
proj - 要应用于元素的投影

[edit] 返回值

一个子范围,从指向第二组第一个元素的迭代器开始,并以等于 last 的迭代器结束。 (2) 返回 std::ranges::dangling 如果 r 是非 borrowed_range 类型的右值。

[edit] 复杂度

给定 N = ranges::distance(first, last),谓词和投影正好应用 N 次。如果 I 模仿 ranges::bidirectional_iterator,最多交换 N / 2 次,否则最多交换 N 次。

[edit] 可能的实现

struct partition_fn
{
    template<std::permutable I, std::sentinel_for<I> S, class Proj = std::identity,
             std::indirect_unary_predicate<std::projected<I, Proj>> Pred>
    constexpr ranges::subrange<I>
        operator()(I first, S last, Pred pred, Proj proj = {}) const
    {
        first = ranges::find_if_not(first, last, std::ref(pred), std::ref(proj));
        if (first == last)
            return {first, first};
 
        for (auto i = ranges::next(first); i != last; ++i)
        {
            if (std::invoke(pred, std::invoke(proj, *i)))
            {
                ranges::iter_swap(i, first);
                ++first;
            }
        }
        return {std::move(first), std::move(last)};
    }
 
    template<ranges::forward_range R, class Proj = std::identity,
             std::indirect_unary_predicate<
                 std::projected<ranges::iterator_t<R>, Proj>> Pred>
    requires std::permutable<ranges::iterator_t<R>>
    constexpr ranges::borrowed_subrange_t<R>
        operator()(R&& r, Pred pred, Proj proj = {}) const
    {
        return (*this)(ranges::begin(r), ranges::end(r),
                       std::ref(pred), std::ref(proj));
    }
};
 
inline constexpr partition_fn partition;

[edit] 示例

#include <algorithm>
#include <forward_list>
#include <functional>
#include <iostream>
#include <iterator>
#include <ranges>
#include <vector>
 
namespace ranges = std::ranges;
 
template<class I, std::sentinel_for<I> S, class Cmp = ranges::less>
requires std::sortable<I, Cmp>
void quicksort(I first, S last, Cmp cmp = Cmp {})
{
    using reference = std::iter_reference_t<I>;
 
    if (first == last)
        return;
 
    auto size = ranges::distance(first, last);
    auto pivot = ranges::next(first, size - 1);
    ranges::iter_swap(pivot, ranges::next(first, size / 2));
 
    auto tail = ranges::partition(first, pivot, [=](reference em)
    {
        return std::invoke(cmp, em, *pivot); // em < pivot
    });
 
    ranges::iter_swap(pivot, tail.begin());
    quicksort(first, tail.begin(), std::ref(cmp));
    quicksort(ranges::next(tail.begin()), last, std::ref(cmp));
}
 
int main()
{
    std::ostream_iterator<int> cout {std::cout, " "};
 
    std::vector<int> v {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    std::cout << "Original vector:  \t";
    ranges::copy(v, cout);
 
    auto tail = ranges::partition(v, [](int i) { return i % 2 == 0; });
 
    std::cout << "\nPartitioned vector: \t";
    ranges::copy(ranges::begin(v), ranges::begin(tail), cout);
    std::cout << "│ ";
    ranges::copy(tail, cout);
 
    std::forward_list<int> fl {1, 30, -4, 3, 5, -4, 1, 6, -8, 2, -5, 64, 1, 92};
    std::cout << "\nUnsorted list: \t\t";
    ranges::copy(fl, cout);
 
    quicksort(ranges::begin(fl), ranges::end(fl), ranges::greater {});
    std::cout << "\nQuick-sorted list: \t";
    ranges::copy(fl, cout);
 
    std::cout << '\n';
}

可能的输出

Original vector:        0 1 2 3 4 5 6 7 8 9
Partitioned vector:     0 8 2 6 4 │ 5 3 7 1 9
Unsorted list:          1 30 -4 3 5 -4 1 6 -8 2 -5 64 1 92
Quick-sorted list:      92 64 30 6 5 3 2 1 1 1 -4 -4 -5 -8

[edit] 另请参阅

复制一个范围,将元素分成两组
(niebloid)[edit]
确定范围是否由给定谓词划分
(niebloid)[edit]
将元素分成两组,同时保留其相对顺序
(niebloid)[edit]
将元素范围分成两组
(函数模板) [edit]