跳到主要内容

std::ranges::partition() 算法

// (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>>
  • Proj - (无)

对于所有重载,Proj 模板参数的默认类型为 std::identity

此外,每个重载都有以下约束

  • (2) - std::permutable<ranges::iterator_t<R>>
  • (1) 重新排列范围 [first; last) 中的元素,使得谓词 pred 返回 true 的所有元素的投影 proj 位于谓词 pred 返回 false 的元素的投影 proj 之前。

    注意

    不保留元素的相对顺序。

  • (2)(1) 相同,但使用 r 作为范围,如同使用 ranges::begin(r) 作为 firstranges::end(r) 作为 last

本页描述的函数类实体是niebloids

参数

first
last

要重新排序的元素范围。

r

要重新排序的元素范围。

pred

应用于投影元素的谓词。

proj

要应用于元素的投影。

返回值

一个子范围,以第二个组的第一个元素的迭代器开始,以等于 last 的迭代器结束。

  • (2) 如果 r 是非 borrowed_range 类型的右值,则返回 std::ranges::dangling

复杂度

给定 Nranges::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;

示例

Main.cpp
#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
本文源自此 CppReference 页面。它可能为了改进或编辑偏好而被修改。点击“编辑此页面”查看本文档的所有更改。
悬停查看原始许可证。

std::ranges::partition() 算法

// (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>>
  • Proj - (无)

对于所有重载,Proj 模板参数的默认类型为 std::identity

此外,每个重载都有以下约束

  • (2) - std::permutable<ranges::iterator_t<R>>
  • (1) 重新排列范围 [first; last) 中的元素,使得谓词 pred 返回 true 的所有元素的投影 proj 位于谓词 pred 返回 false 的元素的投影 proj 之前。

    注意

    不保留元素的相对顺序。

  • (2)(1) 相同,但使用 r 作为范围,如同使用 ranges::begin(r) 作为 firstranges::end(r) 作为 last

本页描述的函数类实体是niebloids

参数

first
last

要重新排序的元素范围。

r

要重新排序的元素范围。

pred

应用于投影元素的谓词。

proj

要应用于元素的投影。

返回值

一个子范围,以第二个组的第一个元素的迭代器开始,以等于 last 的迭代器结束。

  • (2) 如果 r 是非 borrowed_range 类型的右值,则返回 std::ranges::dangling

复杂度

给定 Nranges::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;

示例

Main.cpp
#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
本文源自此 CppReference 页面。它可能为了改进或编辑偏好而被修改。点击“编辑此页面”查看本文档的所有更改。
悬停查看原始许可证。