Difference between revisions of "cpp/algorithm/ranges/inplace merge"
m (→Example: easing iterator req.) |
m (- ranges::) |
||
Line 8: | Line 8: | ||
class Comp = ranges::less, class Proj = std::identity > | class Comp = ranges::less, class Proj = std::identity > | ||
requires std::sortable<I, Comp, Proj> | requires std::sortable<I, Comp, Proj> | ||
− | I | + | I inplace_merge( I first, I middle, S last, Comp comp = {}, Proj proj = {} ); |
}} | }} | ||
{{dcl | num=2 | since=c++20 |1= | {{dcl | num=2 | since=c++20 |1= | ||
Line 15: | Line 15: | ||
requires std::sortable<ranges::iterator_t<R>, Comp, Proj> | requires std::sortable<ranges::iterator_t<R>, Comp, Proj> | ||
ranges::borrowed_iterator_t<R> | ranges::borrowed_iterator_t<R> | ||
− | + | inplace_merge( R&& r, iterator_t<R> middle, Comp comp = {}, Proj proj = {} ); | |
}} | }} | ||
{{dcl end}} | {{dcl end}} |
Revision as of 15:09, 8 July 2021
Defined in header <algorithm>
|
||
Call signature |
||
template< std::bidirectional_iterator I, std::sentinel_for<I> S, class Comp = ranges::less, class Proj = std::identity > |
(1) | (since C++20) |
template< ranges::bidirectional_range R, class Comp = ranges::less, class Proj = std::identity > |
(2) | (since C++20) |
Merges two consecutive sorted ranges [first, middle)
and [middle, last)
into one sorted range [first, last)
.
A sequence is said to be sorted with respect to the comparator comp
and projection proj
if for any iterator it
pointing to the sequence and any non-negative integer n
such that it + n
is a valid iterator pointing to an element of the sequence, std::invoke(comp, std::invoke(proj, *(it + n)), std::invoke(proj, *it))) evaluates to false
.
This merge function is stable, which means that for equivalent elements in the original two ranges, the elements from the first range (preserving their original order) precede the elements from the second range (preserving their original order).
comp
and projection object proj
, and the ranges must be sorted with respect to the same.r
as the range, as if using ranges::begin(r) as first
, and ranges::end(r) as last
.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 |
Parameters
first | - | the beginning of the first sorted range |
middle | - | the end of the first range and the beginning of the second range |
last | - | the end of the second sorted range |
r | - | the range of elements to merge inplace |
comp | - | comparison to apply to the projected elements |
proj | - | projection to apply to the elements in the range. |
Return value
An iterator equal to last
.
Complexity
Exactly N−1 comparisons, if additional memory buffer is available, where N = ranges::distance(first, last). Otherwise, 𝓞(N•log(N))
comparisons. Additionally, twice as many projections as comparisons in both cases.
Notes
This function attempts to allocate a temporary buffer. If the allocation fails, the less efficient algorithm is chosen.
Example
#include <algorithm> #include <complex> #include <functional> #include <iostream> #include <iterator> #include <vector> void print(auto const& v, auto const& rem, int middle = -1) { for (int i{}; auto n : v) std::cout << (i++ == middle ? "│ " : "") << n << ' '; std::cout << rem << '\n'; } template <std::random_access_iterator I, std::sentinel_for<I> S> requires std::sortable<I> void merge_sort(I first, S last) { if (last - first > 1) { I middle {first + (last - first) / 2}; merge_sort(first, middle); merge_sort(middle, last); std::ranges::inplace_merge(first, middle, last); } } int main() { // custom merge-sort demo std::vector v {8, 2, 0, 4, 9, 8, 1, 7, 3}; print(v, ": before sort"); merge_sort(v.begin(), v.end()); print(v, ": after sort\n"); // merging with comparison function object and projection using CI = std::complex<int>; std::vector<CI> r { {0,1}, {0,2}, {0,3}, {1,1}, {1,2} }; const auto middle { std::ranges::next(r.begin(), 3) }; auto comp { std::ranges::less{} }; auto proj { [](CI z) { return z.imag(); } }; print(r, ": before merge", middle - r.begin()); std::ranges::inplace_merge(r, middle, comp, proj); print(r, ": after merge"); }
Output:
8 2 0 4 9 8 1 7 3 : before sort 0 1 2 3 4 7 8 8 9 : after sort (0,1) (0,2) (0,3) │ (1,1) (1,2) : before merge (0,1) (1,1) (0,2) (1,2) (0,3) : after merge
See also
(C++20) |
merges two sorted ranges (niebloid) |
(C++20) |
computes the union of two sets (niebloid) |
(C++20) |
checks whether a range is sorted into ascending order (niebloid) |
(C++20) |
sorts a range into ascending order (niebloid) |
merges two ordered ranges in-place (function template) |