cpp/algorithm/partial sort:修订间差异
YexuanXiao(留言 | 贡献) 小无编辑摘要 |
无编辑摘要 |
||
| 第3行: | 第3行: | ||
{{dcl begin}} | {{dcl begin}} | ||
{{dcl header|algorithm}} | {{dcl header|algorithm}} | ||
{{ | {{|num=1|=c++20| | ||
template< class RandomIt > | template< class RandomIt > | ||
void partial_sort( RandomIt first, RandomIt middle, RandomIt last ); | void partial_sort( RandomIt first, RandomIt middle, RandomIt last ); | ||
}} | }} | ||
{{dcl|since=c++17| | {{dcl|since=c++17| | ||
template< class ExecutionPolicy, class RandomIt > | template< class ExecutionPolicy, class RandomIt > | ||
void partial_sort( ExecutionPolicy&& policy, | void partial_sort( ExecutionPolicy&& policy, | ||
RandomIt first, RandomIt middle, RandomIt last ); | RandomIt first, RandomIt middle, RandomIt last ); | ||
}} | }} | ||
{{ | {{|num=3|=c++20| | ||
template< class RandomIt, class Compare > | template< class RandomIt, class Compare > | ||
void partial_sort( RandomIt first, RandomIt middle, RandomIt last, | void partial_sort( RandomIt first, RandomIt middle, RandomIt last, | ||
Compare comp ); | Compare comp ); | ||
}} | }} | ||
{{dcl|since=c++17| | {{dcl|since=c++17| | ||
template< class ExecutionPolicy, class RandomIt, class Compare > | template< class ExecutionPolicy, class RandomIt, class Compare > | ||
void partial_sort( ExecutionPolicy&& policy, | void partial_sort( ExecutionPolicy&& policy, | ||
| 第36行: | 第29行: | ||
不保证保持相等元素间的顺序。未指定范围 {{range|middle|last}} 中剩余元素的顺序。 | 不保证保持相等元素间的顺序。未指定范围 {{range|middle|last}} 中剩余元素的顺序。 | ||
@1@ | @1@ {{c|operator<}} 。 | ||
@3@ | |||
@2,4@ 同 {{v|1,3}},但按照 {{c|policy}} 执行。{{cpp/algorithm/parallel overload precondition|plural=yes}} | @3@ {{c|comp}} 。 | ||
@2,4@ 同 {{v|1,3}},但按照 {{c|policy}} 执行。 | |||
{{cpp/algorithm/parallel overload precondition|plural=yes | |||
}} | |||
===参数=== | ===参数=== | ||
{{par begin}} | {{par begin}} | ||
{{par | first, last |定义范围的随机访问迭代器}} | {{par|first, last|定义范围的随机访问迭代器}} | ||
{{par | middle |定义要排序的范围的末尾后一位置的随机访问迭代器}} | {{par|middle|定义要排序的范围的末尾后一位置的随机访问迭代器}} | ||
{{par exec pol}} | {{par exec pol}} | ||
{{par cmp ord | comp | p1=RandomIt}} | {{par cmp ord|comp|p1=RandomIt}} | ||
{{par hreq}} | {{par hreq}} | ||
{{par req named | RandomIt | RandomAccessIterator | {{par req named|RandomIt|RandomAccessIterator}} | ||
{{par req named | {{par req named||}} | ||
{{par end}} | {{par end}} | ||
===复杂度=== | ===复杂度=== | ||
{{|(last - first | |||
) | |||
log()}} 次{{c|}}。 | |||
===异常=== | ===异常=== | ||
{{cpp/algorithm/ | {{cpp/algorithm/|singular=no}} | ||
===可能的实现=== | ===可能的实现=== | ||
| 第76行: | 第73行: | ||
|title1=partial_sort (1)|ver1=1|1= | |title1=partial_sort (1)|ver1=1|1= | ||
template<typename RandomIt> | template<typename RandomIt> | ||
// C++20 起 | //C++20 起 | ||
void partial_sort(RandomIt first, RandomIt middle, RandomIt last) | void partial_sort(RandomIt first, RandomIt middle, RandomIt last) | ||
{ | { | ||
| 第86行: | 第83行: | ||
{ | { | ||
template<typename RandomIt, typename Compare> | template<typename RandomIt, typename Compare> | ||
// | // | ||
void sift_down(RandomIt first, RandomIt last, const Compare& comp) | void sift_down(RandomIt first, RandomIt last, const Compare& comp) | ||
{ | { | ||
// | // | ||
const auto length = static_cast<size_t>(last - first); | const auto length = static_cast<size_t>(last - first); | ||
std::size_t current = 0; | std::size_t current = 0; | ||
std::size_t next = 2; | std::size_t next = 2; | ||
| 第107行: | 第104行: | ||
std::iter_swap(first + current, first + next); | std::iter_swap(first + current, first + next); | ||
} | } | ||
template<typename RandomIt, typename Compare> | template<typename RandomIt, typename Compare> | ||
// | // | ||
void heap_select(RandomIt first, RandomIt middle, RandomIt last, const Compare& comp) | void heap_select(RandomIt first, RandomIt middle, RandomIt last, const Compare& comp) | ||
{ | { | ||
| 第125行: | 第122行: | ||
template<typename RandomIt, typename Compare> | template<typename RandomIt, typename Compare> | ||
// C++20 起 | //C++20 起 | ||
void partial_sort(RandomIt first, RandomIt middle, RandomIt last, Compare comp) | void partial_sort(RandomIt first, RandomIt middle, RandomIt last, Compare comp) | ||
{ | { | ||
| 第132行: | 第129行: | ||
} | } | ||
}} | }} | ||
===示例=== | ===示例=== | ||
| 第141行: | 第149行: | ||
#include <iostream> | #include <iostream> | ||
void print(auto | void print(auto& s, int middle) | ||
{ | { | ||
for (int a : s) | for (int a : s) | ||
| 第185行: | 第193行: | ||
^---------- | ^---------- | ||
}} | }} | ||
===参阅=== | ===参阅=== | ||
2024年4月2日 (二) 07:28的版本
| 在标头 <algorithm> 定义
|
||
| (1) | (C++20 起为 constexpr) |
|
| |
(2) | (C++17 起) |
| (3) | (C++20 起为 constexpr) |
|
| |
(4) | (C++17 起) |
重排元素,使得范围 [first, middle) 含有范围 [first, last) 中已排序的 middle - first 个最小元素。
不保证保持相等元素间的顺序。未指定范围 [middle, last) 中剩余元素的顺序。
comp 进行排序。policy 执行。|
|
(C++20 前) |
|
|
(C++20 起) |
如果满足以下任意条件,那么行为未定义:
[first,middle)或[middle,last)不是有效范围。
|
(C++11 前) |
|
(C++11 起) |
参数
| first, last | - | 定义范围的随机访问迭代器 |
| middle | - | 定义要排序的范围的末尾后一位置的随机访问迭代器 |
| policy | - | 所用的执行策略 |
| comp | - | 比较函数对象(即满足比较 (Compare) 概念的对象),在第一参数小于(即先 序于)第二参数时返回 true。比较函数的签名应等价于如下:
虽然签名不必有 |
| 类型要求 | ||
-RandomIt 必须满足老式随机访问迭代器 (LegacyRandomAccessIterator) 。
| ||
-Compare 必须满足比较 (Compare) 。
| ||
复杂度
给定 M 为 middle - first,N 为 last - first:
operator<(C++20 前)std::less{}(C++20 起) 进行比较。comp。异常
拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误:
- 如果作为算法一部分调用的函数的执行抛出异常,且
ExecutionPolicy是标准策略之一,那么调用 std::terminate。对于任何其他ExecutionPolicy,行为由实现定义。 - 如果算法无法分配内存,那么抛出 std::bad_alloc。
可能的实现
| partial_sort (1) |
|---|
template<typename RandomIt>
constexpr //< C++20 起
void partial_sort(RandomIt first, RandomIt middle, RandomIt last)
{
typedef typename std::iterator_traits<RandomIt>::value_type VT;
std::partial_sort(first, middle, last, std::less<VT>());
}
|
| partial_sort (3) |
namespace impl
{
template<typename RandomIt, typename Compare>
constexpr //< C++20 起
void sift_down(RandomIt first, RandomIt last, const Compare& comp)
{
// 筛出 “first” 位置的元素
const auto length = static_cast<std::size_t>(last - first);
std::size_t current = 0;
std::size_t next = 2;
while (next < length)
{
if (comp(*(first + next), *(first + (next - 1))))
--next;
if (!comp(*(first + current), *(first + next)))
return;
std::iter_swap(first + current, first + next);
current = next;
next = 2 * current + 2;
}
--next;
if (next < length && comp(*(first + current), *(first + next)))
std::iter_swap(first + current, first + next);
}
template<typename RandomIt, typename Compare>
constexpr //< C++20 起
void heap_select(RandomIt first, RandomIt middle, RandomIt last, const Compare& comp)
{
std::make_heap(first, middle, comp);
for (auto i = middle; i != last; ++i)
{
if (comp(*i, *first))
{
std::iter_swap(first, i);
sift_down(first, middle, comp);
}
}
}
} // namespace impl
template<typename RandomIt, typename Compare>
constexpr //< C++20 起
void partial_sort(RandomIt first, RandomIt middle, RandomIt last, Compare comp)
{
impl::heap_select(first, middle, last, comp);
std::sort_heap(first, middle, comp);
}
|
注解
算法
典型采用堆选取 算法来选择最小元素,并采用堆排序 算法以升序对从堆中选取的元素进行排序。
使用堆来进行元素的选取(见 堆)。例如,当以 operator< 为比较函数时,使用最大堆 来选取 middle − first 个最小元素。
选择完成后用堆排序对所选取的 [first, middle) 个元素进行排序(见 std::sort_heap)。
预期用途
std::partial_sort 算法预期被用于少量常数个数的 [first, middle) 选取元素。
示例
#include <algorithm>
#include <array>
#include <functional>
#include <iostream>
void print(const auto& s, int middle)
{
for (int a : s)
std::cout << a << ' ';
std::cout << '\n';
if (middle > 0)
{
while (middle-- > 0)
std::cout << "--";
std::cout << '^';
}
else if (middle < 0)
{
for (auto i = s.size() + middle; --i; std::cout << " ")
{}
for (std::cout << '^'; middle++ < 0; std::cout << "--")
{}
}
std::cout << '\n';
};
int main()
{
std::array<int, 10> s{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
print(s, 0);
std::partial_sort(s.begin(), s.begin() + 3, s.end());
print(s, 3);
std::partial_sort(s.rbegin(), s.rbegin() + 4, s.rend());
print(s, -4);
std::partial_sort(s.rbegin(), s.rbegin() + 5, s.rend(), std::greater{});
print(s, -5);
}
可能的输出:
5 7 4 2 8 6 1 9 0 3
0 1 2 7 8 6 5 9 4 3
------^
4 5 6 7 8 9 3 2 1 0
^--------
4 3 2 1 0 5 6 7 8 9
^----------
缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
| 缺陷报告 | 应用于 | 出版时的行为 | 正确行为 |
|---|---|---|---|
| P0896R4 | C++98 | [first, middle) 和 [middle, last) 不需要有效
|
其中之一无效时行为未定义 |
参阅
| 将给定范围部分排序,确保其按给定元素划分 (函数模板) | |
| 复制范围中元素并部分排序 (函数模板) | |
| 将范围中元素排序,同时保持相等元之间的顺序 (函数模板) | |
| 将范围按升序排序 (函数模板) | |
(C++20) |
将范围中前 N 个元素排序 (算法函数对象) |