std::ranges::partition() 算法
- 自 C++20 起
- 简化
- 详细
// (1)
constexpr ranges::subrange<I>
partition( I first, S last, Pred pred, Proj proj = {} );
// (2)
constexpr ranges::borrowed_subrange_t<R>
partition( R&& r, Pred pred, Proj proj = {} );
参数类型是泛型的,并具有以下约束
I
-std::permutable
S
-std::sentinel_for<I>
R
-std::ranges::forward_range
Pred
:- (1) -
std::indirect_unary_predicate<std::projected<I, Proj>>
- (2) -
std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>>
- (1) -
Proj
- (无)
对于所有重载,Proj
模板参数的默认类型为 std::identity
。
此外,每个重载都有以下约束
- (2) -
std::permutable<ranges::iterator_t<R>>
// (1)
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 = {} );
// (2)
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 = {} );
-
(1) 重新排列范围 [
first
;last
) 中的元素,使得谓词pred
返回true
的所有元素的投影proj
位于谓词pred
返回false
的元素的投影proj
之前。注意不保留元素的相对顺序。
-
(2) 与 (1) 相同,但使用
r
作为范围,如同使用ranges::begin(r)
作为first
和ranges::end(r)
作为last
。
本页描述的函数类实体是niebloids。
参数
first last | 要重新排序的元素范围。 |
r | 要重新排序的元素范围。 |
pred | 应用于投影元素的谓词。 |
proj | 要应用于元素的投影。 |
返回值
一个子范围,以第二个组的第一个元素的迭代器开始,以等于 last
的迭代器结束。
- (2) 如果
r
是非borrowed_range
类型的右值,则返回std::ranges::dangling
。
复杂度
给定 N
为 ranges::distance(first, last)
谓词和投影的精确 N
次应用。
如果 I
建模 ranges::bidirectional_iterator
,则最多 N / 2
次交换,否则最多 N
次交换。
异常
(无)
可能的实现
partition(1) 和 partition(2)
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;
示例
#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