Difference between revisions of "cpp/algorithm/ranges/partial sort copy"
m (mathjax-or) |
Andreas Krug (Talk | contribs) m (fmt) |
||
(4 intermediate revisions by 4 users not shown) | |||
Line 2: | Line 2: | ||
{{cpp/algorithm/ranges/navbar}} | {{cpp/algorithm/ranges/navbar}} | ||
{{dcl begin}} | {{dcl begin}} | ||
− | {{dcl header | algorithm}} | + | {{dcl header|algorithm}} |
− | {{dcl h | Call signature}} | + | {{dcl h|Call signature}} |
− | {{dcl | num=1 | since=c++20 |1= | + | {{dcl|num=1|since=c++20|1= |
template< std::input_iterator I1, std::sentinel_for<I1> S1, | template< std::input_iterator I1, std::sentinel_for<I1> S1, | ||
std::random_access_iterator I2, std::sentinel_for<I2> S2, | std::random_access_iterator I2, std::sentinel_for<I2> S2, | ||
class Comp = ranges::less, class Proj1 = std::identity, | class Comp = ranges::less, class Proj1 = std::identity, | ||
class Proj2 = std::identity > | class Proj2 = std::identity > | ||
− | requires | + | requires std::indirectly_copyable<I1, I2> && |
− | + | std::sortable<I2, Comp, Proj2> && | |
− | + | std::indirect_strict_weak_order<Comp, std::projected<I1, Proj1>, | |
+ | std::projected<I2, Proj2>> | ||
constexpr partial_sort_copy_result<I1, I2> | constexpr partial_sort_copy_result<I1, I2> | ||
− | + | partial_sort_copy( I1 first, S1 last, I2 result_first, S2 result_last, | |
− | + | Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {} ); | |
}} | }} | ||
− | {{dcl | num=2 | since=c++20 |1= | + | {{dcl|num=2|since=c++20|1= |
template< ranges::input_range R1, ranges::random_access_range R2, | template< ranges::input_range R1, ranges::random_access_range R2, | ||
class Comp = ranges::less, class Proj1 = std::identity, | class Comp = ranges::less, class Proj1 = std::identity, | ||
class Proj2 = std::identity > | class Proj2 = std::identity > | ||
− | requires | + | requires std::indirectly_copyable<ranges::iterator_t<R1>, ranges::iterator_t<R2>> && |
− | + | std::sortable<ranges::iterator_t<R2>, Comp, Proj2> && | |
− | + | std::indirect_strict_weak_order<Comp, std::projected<ranges::iterator_t<R1>, | |
− | + | Proj1>, std::projected<ranges::iterator_t<R2>, Proj2>> | |
constexpr partial_sort_copy_result<ranges::borrowed_iterator_t<R1>, | constexpr partial_sort_copy_result<ranges::borrowed_iterator_t<R1>, | ||
ranges::borrowed_iterator_t<R2>> | ranges::borrowed_iterator_t<R2>> | ||
− | + | partial_sort_copy( R1&& r, R2&& result_r, | |
− | + | Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {} ); | |
}} | }} | ||
− | {{dcl h | Helper types}} | + | {{dcl h|Helper types}} |
− | {{dcl | num=3 | since=c++20 |1= | + | {{dcl|num=3|since=c++20|1= |
− | template<class I, class O> | + | template< class I, class O > |
using partial_sort_copy_result = ranges::in_out_result<I, O>; | using partial_sort_copy_result = ranges::in_out_result<I, O>; | ||
}} | }} | ||
{{dcl end}} | {{dcl end}} | ||
− | Copies the first {{ | + | Copies the first {{c|N}} elements from the source range {{range|first|last}}, as if it was partially sorted with respect to {{c|comp}} and {{c|proj1}}, into the destination range {{range|result_first|result_first + N}}, where {{mathjax-or|1=\(\scriptsize N = \min{(L_1, L_2)}\)|2=N = min(L₁, L₂)}}, {{mathjax-or|\(\scriptsize L_1\)|L₁}} is equal to {{c|ranges::distance(first, last)}}, and {{mathjax-or|\(\scriptsize L_2\)|L₂}} is equal to {{c|ranges::distance(result_first, result_last)}}. |
The order of equal elements is ''not'' guaranteed to be preserved. | The order of equal elements is ''not'' guaranteed to be preserved. | ||
− | @1@ The source range elements are projected using the function object {{ | + | @1@ The source range elements are projected using the function object {{c|proj1}}, and the destination elements are projected using the function object {{c|proj2}}. |
− | @2@ Same as {{v|1}}, but uses {{ | + | @2@ Same as {{v|1}}, but uses {{c|r}} as the source range and {{c|result_r}} as the destination range, as if using {{c|ranges::begin(r)}} as {{c|first}}, {{c|ranges::end(r)}} as {{c|last}}, {{c|ranges::begin(result_r)}} as {{c|result_first}}, and {{c|ranges::end(result_r)}} as {{c|result_last}}. |
{{cpp/ranges/niebloid}} | {{cpp/ranges/niebloid}} | ||
Line 48: | Line 49: | ||
===Parameters=== | ===Parameters=== | ||
{{par begin}} | {{par begin}} | ||
− | {{par | first, last | iterator-sentinel defining the source range to copy from}} | + | {{par|first, last|iterator-sentinel defining the source range to copy from}} |
− | {{par | r | the source range to copy from}} | + | {{par|r|the source range to copy from}} |
− | {{par | result_first, result_last | iterator-sentinel defining the destination range}} | + | {{par|result_first, result_last|iterator-sentinel defining the destination range}} |
− | {{par | result_r | the destination range}} | + | {{par|result_r|the destination range}} |
− | {{par | comp | comparison to apply to the projected elements}} | + | {{par|comp|comparison to apply to the projected elements}} |
− | {{par | proj1 | projection to apply to the elements of source range}} | + | {{par|proj1|projection to apply to the elements of source range}} |
− | {{par | proj2 | projection to apply to the elements of destination range}} | + | {{par|proj2|projection to apply to the elements of destination range}} |
{{par end}} | {{par end}} | ||
Line 64: | Line 65: | ||
===Possible implementation=== | ===Possible implementation=== | ||
− | {{eq fun | 1= | + | {{eq fun|1= |
− | struct partial_sort_copy_fn { | + | struct partial_sort_copy_fn |
− | template< std::input_iterator I1, std::sentinel_for<I1> S1, | + | { |
− | + | template<std::input_iterator I1, std::sentinel_for<I1> S1, | |
− | + | std::random_access_iterator I2, std::sentinel_for<I2> S2, | |
− | + | class Comp = ranges::less, class Proj1 = std::identity, | |
− | requires | + | class Proj2 = std::identity> |
− | + | requires std::indirectly_copyable<I1, I2> && std::sortable<I2, Comp, Proj2> && | |
− | + | std::indirect_strict_weak_order<Comp, std::projected<I1, Proj1>, | |
+ | std::projected<I2, Proj2>> | ||
constexpr ranges::partial_sort_copy_result<I1, I2> | constexpr ranges::partial_sort_copy_result<I1, I2> | ||
− | + | operator()(I1 first, S1 last, I2 result_first, S2 result_last, | |
− | + | Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const | |
− | if (result_first == result_last) | + | { |
+ | if (result_first == result_last) | ||
return {std::move(ranges::next(std::move(first), std::move(last))), | return {std::move(ranges::next(std::move(first), std::move(last))), | ||
std::move(result_first)}; | std::move(result_first)}; | ||
− | |||
− | auto out_last {result_first}; | + | auto out_last{result_first}; |
// copy first N elements | // copy first N elements | ||
− | for (; !(first == last or out_last == result_last); ++out_last, ++first) | + | for (; !(first == last or out_last == result_last); ++out_last, ++first) |
*out_last = *first; | *out_last = *first; | ||
− | + | ||
// convert N copied elements into a max-heap | // convert N copied elements into a max-heap | ||
ranges::make_heap(result_first, out_last, comp, proj2); | ranges::make_heap(result_first, out_last, comp, proj2); | ||
// process the rest of the input range (if any), preserving the heap property | // process the rest of the input range (if any), preserving the heap property | ||
− | for (; first != last; ++first) { | + | for (; first != last; ++first) |
− | if (std::invoke(comp, std::invoke(proj1, *first), std::invoke(proj2, *result_first))) { | + | { |
+ | if (std::invoke(comp, std::invoke(proj1, *first), | ||
+ | std::invoke(proj2, *result_first))) | ||
+ | { | ||
// pop out the biggest item and push in a newly found smaller one | // pop out the biggest item and push in a newly found smaller one | ||
ranges::pop_heap(result_first, out_last, comp, proj2); | ranges::pop_heap(result_first, out_last, comp, proj2); | ||
Line 99: | Line 104: | ||
} | } | ||
− | // first N elements in the output range is still a heap - convert it into a sorted range | + | // first N elements in the output range is still |
+ | // a heap - convert it into a sorted range | ||
ranges::sort_heap(result_first, out_last, comp, proj2); | ranges::sort_heap(result_first, out_last, comp, proj2); | ||
Line 105: | Line 111: | ||
} | } | ||
− | template< ranges::input_range R1, ranges::random_access_range R2, | + | template<ranges::input_range R1, ranges::random_access_range R2, |
− | + | class Comp = ranges::less, class Proj1 = std::identity, | |
− | + | class Proj2 = std::identity> | |
− | requires | + | requires std::indirectly_copyable<ranges::iterator_t<R1>, ranges::iterator_t<R2>> && |
− | + | std::sortable<ranges::iterator_t<R2>, Comp, Proj2> && | |
− | + | std::indirect_strict_weak_order<Comp, std::projected<ranges::iterator_t<R1>, | |
− | + | Proj1>, std::projected<ranges::iterator_t<R2>, Proj2>> | |
constexpr ranges::partial_sort_copy_result<ranges::borrowed_iterator_t<R1>, | constexpr ranges::partial_sort_copy_result<ranges::borrowed_iterator_t<R1>, | ||
ranges::borrowed_iterator_t<R2>> | ranges::borrowed_iterator_t<R2>> | ||
− | + | operator()(R1&& r, R2&& result_r, Comp comp = {}, | |
− | + | Proj1 proj1 = {}, Proj2 proj2 = {}) const | |
+ | { | ||
return (*this)(ranges::begin(r), ranges::end(r), | return (*this)(ranges::begin(r), ranges::end(r), | ||
ranges::begin(result_r), ranges::end(result_r), | ranges::begin(result_r), ranges::end(result_r), | ||
Line 122: | Line 129: | ||
}; | }; | ||
− | inline constexpr partial_sort_copy_fn partial_sort_copy{}; | + | inline constexpr partial_sort_copy_fn partial_sort_copy {}; |
}} | }} | ||
===Example=== | ===Example=== | ||
− | {{example| code= | + | {{example |
+ | |code= | ||
#include <algorithm> | #include <algorithm> | ||
#include <forward_list> | #include <forward_list> | ||
Line 162: | Line 170: | ||
print("partial_sort_copy: ", dest2); | print("partial_sort_copy: ", dest2); | ||
} | } | ||
− | + | |output= | |
Write to the smaller vector in ascending order: | Write to the smaller vector in ascending order: | ||
const source list: 4 2 5 1 3 | const source list: 4 2 5 1 3 | ||
Line 175: | Line 183: | ||
===See also=== | ===See also=== | ||
{{dsc begin}} | {{dsc begin}} | ||
− | {{dsc inc | cpp/algorithm/ranges/dsc partial_sort}} | + | {{dsc inc|cpp/algorithm/ranges/dsc partial_sort}} |
− | {{dsc inc | cpp/algorithm/ranges/dsc sort}} | + | {{dsc inc|cpp/algorithm/ranges/dsc sort}} |
− | {{dsc inc | cpp/algorithm/ranges/dsc stable_sort}} | + | {{dsc inc|cpp/algorithm/ranges/dsc stable_sort}} |
− | {{dsc inc | cpp/algorithm/ranges/dsc sort_heap}} | + | {{dsc inc|cpp/algorithm/ranges/dsc sort_heap}} |
− | {{dsc inc | cpp/algorithm/ranges/dsc make_heap}} | + | {{dsc inc|cpp/algorithm/ranges/dsc make_heap}} |
− | {{dsc inc | cpp/algorithm/ranges/dsc push_heap}} | + | {{dsc inc|cpp/algorithm/ranges/dsc push_heap}} |
− | {{dsc inc | cpp/algorithm/ranges/dsc pop_heap}} | + | {{dsc inc|cpp/algorithm/ranges/dsc pop_heap}} |
− | {{dsc inc | cpp/algorithm/dsc partial_sort_copy}} | + | {{dsc inc|cpp/algorithm/dsc partial_sort_copy}} |
{{dsc end}} | {{dsc end}} | ||
{{langlinks|de|es|fr|it|ja|pt|ru|zh}} | {{langlinks|de|es|fr|it|ja|pt|ru|zh}} |
Latest revision as of 23:50, 23 September 2023
Defined in header <algorithm>
|
||
Call signature |
||
template< std::input_iterator I1, std::sentinel_for<I1> S1, std::random_access_iterator I2, std::sentinel_for<I2> S2, |
(1) | (since C++20) |
template< ranges::input_range R1, ranges::random_access_range R2, class Comp = ranges::less, class Proj1 = std::identity, |
(2) | (since C++20) |
Helper types |
||
template< class I, class O > using partial_sort_copy_result = ranges::in_out_result<I, O>; |
(3) | (since C++20) |
Copies the first N elements from the source range [
first,
last)
, as if it was partially sorted with respect to comp and proj1, into the destination range [
result_first,
result_first + N)
, where N = min(L₁, L₂), L₁ is equal to ranges::distance(first, last), and L₂ is equal to ranges::distance(result_first, result_last).
The order of equal elements is not guaranteed to be preserved.
The function-like entities described on this page are niebloids, that is:
- Explicit template argument lists cannot be specified when calling any of them.
- None of them are visible to argument-dependent lookup.
- When any of them are found by normal unqualified lookup as the name to the left of the function-call operator, argument-dependent lookup is inhibited.
In practice, they may be implemented as function objects, or with special compiler extensions.
Contents |
[edit] Parameters
first, last | - | iterator-sentinel defining the source range to copy from |
r | - | the source range to copy from |
result_first, result_last | - | iterator-sentinel defining the destination range |
result_r | - | the destination range |
comp | - | comparison to apply to the projected elements |
proj1 | - | projection to apply to the elements of source range |
proj2 | - | projection to apply to the elements of destination range |
[edit] Return value
An object equal to {last, result_first + N}.
[edit] Complexity
At most L₁•log(N) comparisons and 2•L₁•log(N) projections.
[edit] Possible implementation
struct partial_sort_copy_fn { template<std::input_iterator I1, std::sentinel_for<I1> S1, std::random_access_iterator I2, std::sentinel_for<I2> S2, class Comp = ranges::less, class Proj1 = std::identity, class Proj2 = std::identity> requires std::indirectly_copyable<I1, I2> && std::sortable<I2, Comp, Proj2> && std::indirect_strict_weak_order<Comp, std::projected<I1, Proj1>, std::projected<I2, Proj2>> constexpr ranges::partial_sort_copy_result<I1, I2> operator()(I1 first, S1 last, I2 result_first, S2 result_last, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const { if (result_first == result_last) return {std::move(ranges::next(std::move(first), std::move(last))), std::move(result_first)}; auto out_last{result_first}; // copy first N elements for (; !(first == last or out_last == result_last); ++out_last, ++first) *out_last = *first; // convert N copied elements into a max-heap ranges::make_heap(result_first, out_last, comp, proj2); // process the rest of the input range (if any), preserving the heap property for (; first != last; ++first) { if (std::invoke(comp, std::invoke(proj1, *first), std::invoke(proj2, *result_first))) { // pop out the biggest item and push in a newly found smaller one ranges::pop_heap(result_first, out_last, comp, proj2); *(out_last - 1) = *first; ranges::push_heap(result_first, out_last, comp, proj2); } } // first N elements in the output range is still // a heap - convert it into a sorted range ranges::sort_heap(result_first, out_last, comp, proj2); return {std::move(first), std::move(out_last)}; } template<ranges::input_range R1, ranges::random_access_range R2, class Comp = ranges::less, class Proj1 = std::identity, class Proj2 = std::identity> requires std::indirectly_copyable<ranges::iterator_t<R1>, ranges::iterator_t<R2>> && std::sortable<ranges::iterator_t<R2>, Comp, Proj2> && std::indirect_strict_weak_order<Comp, std::projected<ranges::iterator_t<R1>, Proj1>, std::projected<ranges::iterator_t<R2>, Proj2>> constexpr ranges::partial_sort_copy_result<ranges::borrowed_iterator_t<R1>, ranges::borrowed_iterator_t<R2>> operator()(R1&& r, R2&& result_r, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const { return (*this)(ranges::begin(r), ranges::end(r), ranges::begin(result_r), ranges::end(result_r), std::move(comp), std::move(proj1), std::move(proj2)); } }; inline constexpr partial_sort_copy_fn partial_sort_copy {}; |
[edit] Example
#include <algorithm> #include <forward_list> #include <functional> #include <iostream> #include <ranges> #include <string_view> #include <vector> void print(std::string_view rem, std::ranges::input_range auto const& v) { for (std::cout << rem; const auto& e : v) std::cout << e << ' '; std::cout << '\n'; } int main() { const std::forward_list source{4, 2, 5, 1, 3}; print("Write to the smaller vector in ascending order: ", ""); std::vector dest1{10, 11, 12}; print("const source list: ", source); print("destination range: ", dest1); std::ranges::partial_sort_copy(source, dest1); print("partial_sort_copy: ", dest1); print("Write to the larger vector in descending order:", ""); std::vector dest2{10, 11, 12, 13, 14, 15, 16}; print("const source list: ", source); print("destination range: ", dest2); std::ranges::partial_sort_copy(source, dest2, std::greater{}); print("partial_sort_copy: ", dest2); }
Output:
Write to the smaller vector in ascending order: const source list: 4 2 5 1 3 destination range: 10 11 12 partial_sort_copy: 1 2 3 Write to the larger vector in descending order: const source list: 4 2 5 1 3 destination range: 10 11 12 13 14 15 16 partial_sort_copy: 5 4 3 2 1 15 16
[edit] See also
(C++20) |
sorts the first N elements of a range (niebloid) |
(C++20) |
sorts a range into ascending order (niebloid) |
(C++20) |
sorts a range of elements while preserving order between equal elements (niebloid) |
(C++20) |
turns a max heap into a range of elements sorted in ascending order (niebloid) |
(C++20) |
creates a max heap out of a range of elements (niebloid) |
(C++20) |
adds an element to a max heap (niebloid) |
(C++20) |
removes the largest element from a max heap (niebloid) |
copies and partially sorts a range of elements (function template) |