std::ranges::merge, std::ranges::merge_result
| Определён в заголовке <algorithm>
|
||
| Сигнатура вызова |
||
template< std::input_iterator I1, std::sentinel_for<I1> S1,
std::input_iterator I2, std::sentinel_for<I2> S2,
std::weakly_incrementable O, class Comp = ranges::less,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::mergeable<I1, I2, O, Comp, Proj1, Proj2>
constexpr merge_result<I1, I2, O>
merge( I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {},
Proj1 proj1 = {}, Proj2 proj2 = {} );
|
(1) | (начиная с C++20) |
template< ranges::input_range R1, ranges::input_range R2,
std::weakly_incrementable O, class Comp = ranges::less,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::mergeable<ranges::iterator_t<R1>, ranges::iterator_t<R2>,
O, Comp, Proj1, Proj2>
constexpr merge_result<ranges::borrowed_iterator_t<R1>,
ranges::borrowed_iterator_t<R2>, O>
merge( R1&& r1, R2&& r2, O result, Comp comp = {},
Proj1 proj1 = {}, Proj2 proj2 = {} );
|
(2) | (начиная с C++20) |
| Вспомогательные типы |
||
template< class I1, class I2, class O >
using merge_result = ranges::in_in_out_result<I1, I2, O>;
|
(3) | (начиная с C++20) |
Объединяет два отсортированных диапазона [[first1, last1) и [first2, last2) в один отсортированный диапазон, начинающийся с result.
Последовательность считается отсортированной относительно компаратора comp если для любого итератора it указывающего на последовательность и любого неотрицательного целого числа n такого, что it + n является допустимым итератором, указывающим на элемент последовательности, std::invoke(comp, std::invoke(proj2, *(it + n)), std::invoke(proj1, *it))) вычисляется в false.
comp.r1 в качестве первого диапазона и r2 в качестве второго диапазона, как если бы использовались ranges::begin(r1) как first1, ranges::end(r1) как last1, ranges::begin(r2) как first2 и ranges::end(r2) как last2.Поведение не определено, если целевой диапазон перекрывается с любым из входных диапазонов (входные диапазоны могут перекрываться друг с другом).
Данная функция слияния является устойчивой, то есть для эквивалентных элементов в исходных двух диапазонах элементы из первого диапазона (с сохранением их исходного порядка) предшествуют элементам из второго диапазона (с сохранением их исходного порядка).
Сущности, подобные функциям, описанные на этой странице, являются объектами-функциями алгоритмов (неформально известными как niebloids), то есть:
- Явные списки аргументов шаблона не могут быть указаны при вызове любого из них.
- Ни один из них не видим при поиске, зависящем от аргументов.
- Когда любой из них находится обычным неквалифицированным поиском как имя слева от оператора вызова функции, поиск, зависящий от аргументов подавляется.
Параметры
| first1, last1 | - | пара итератор-страж, определяющая первый входной отсортированный range элементов для слияния |
| first2, last2 | - | пара итератор-страж, определяющая второй входной отсортированный range элементов для слияния |
| result | - | начало выходного диапазона |
| comp | - | функция сравнения, применяемая к проецируемым элементам |
| proj1 | - | проекция, применяемая к элементам в первом диапазоне |
| proj2 | - | проекция, применяемая к элементам во втором диапазоне |
Возвращаемое значение
{ last1, last2, result_last } , где result_last является концом построенного диапазона.
Сложность
Не более N − 1 сравнений и применений каждой проекции, где N = ranges:: distance ( first1, last1 ) + ranges:: distance ( first2, last12 ) .
Примечания
Этот алгоритм выполняет схожую задачу с ranges:: set_union . Оба обрабатывают два отсортированных входных диапазона и выдают отсортированный выходной диапазон с элементами из обоих входов. Разница между этими двумя алгоритмами заключается в обработке значений из обоих входных диапазонов, которые сравниваются как эквивалентные (см. примечания к LessThanComparable ). Если любые эквивалентные значения появлялись n раз в первом диапазоне и m раз во втором, ranges::merge выведет все n + m вхождений, тогда как ranges::set_union выведет только max ( n, m ) . Таким образом, ranges::merge выдает ровно N значений, а ranges::set_union может выдать меньше.
Возможная реализация
struct merge_fn { template<std::input_iterator I1, std::sentinel_for<I1> S1, std::input_iterator I2, std::sentinel_for<I2> S2, std::weakly_incrementable O, class Comp = ranges::less, class Proj1 = std::identity, class Proj2 = std::identity> requires std::mergeable<I1, I2, O, Comp, Proj1, Proj2> constexpr ranges::merge_result<I1, I2, O> operator()(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const { for (; !(first1 == last1 or first2 == last2); ++result) { if (std::invoke(comp, std::invoke(proj2, *first2), std::invoke(proj1, *first1))) *result = *first2, ++first2; else *result = *first1, ++first1; } auto ret1{ranges::copy(std::move(first1), std::move(last1), std::move(result))}; auto ret2{ranges::copy(std::move(first2), std::move(last2), std::move(ret1.out))}; return {std::move(ret1.in), std::move(ret2.in), std::move(ret2.out)}; } template<ranges::input_range R1, ranges::input_range R2, std::weakly_incrementable O, class Comp = ranges::less, class Proj1 = std::identity, class Proj2 = std::identity> requires std::mergeable<ranges::iterator_t<R1>, ranges::iterator_t<R2>, O, Comp, Proj1, Proj2> constexpr ranges::merge_result<ranges::borrowed_iterator_t<R1>, ranges::borrowed_iterator_t<R2>, O> operator()(R1&& r1, R2&& r2, O result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const { return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), std::move(result), std::move(comp), std::move(proj1), std::move(proj2)); } }; inline constexpr merge_fn merge {}; |
Пример
#include <algorithm> #include <iostream> #include <iterator> #include <vector> void print(const auto& in1, const auto& in2, auto first, auto last) { std::cout << "{ "; for (const auto& e : in1) std::cout << e << ' '; std::cout << "} +\n{ "; for (const auto& e : in2) std::cout << e << ' '; std::cout << "} =\n{ "; while (!(first == last)) std::cout << *first++ << ' '; std::cout << "}\n\n"; } int main() { std::vector<int> in1, in2, out; in1 = {1, 2, 3, 4, 5}; in2 = {3, 4, 5, 6, 7}; out.resize(in1.size() + in2.size()); const auto ret = std::ranges::merge(in1, in2, out.begin()); print(in1, in2, out.begin(), ret.out); in1 = {1, 2, 3, 4, 5, 5, 5}; in2 = {3, 4, 5, 6, 7}; out.clear(); out.reserve(in1.size() + in2.size()); std::ranges::merge(in1, in2, std::back_inserter(out)); print(in1, in2, out.cbegin(), out.cend()); }
Вывод:
{ 1 2 3 4 5 } +
{ 3 4 5 6 7 } =
{ 1 2 3 3 4 4 5 5 6 7 }
{ 1 2 3 4 5 5 5 } +
{ 3 4 5 6 7 } =
{ 1 2 3 3 4 4 5 5 5 5 6 7 }
См. также
(C++20) |
сливает два упорядоченных диапазона на месте (объект-функция алгоритма) |
(C++20) |
проверяет, отсортирован ли диапазон (объект-функция алгоритма) |
(C++20) |
вычисляет объединение двух множеств (объект-функция алгоритма) |
(C++20) |
сортирует диапазон элементов (объект-функция алгоритма) |
(C++20) |
сортирует диапазон элементов, сохраняя относительный порядок эквивалентных элементов (объект-функция алгоритма) |
| сливает два отсортированных диапазона (шаблон функции) |