Spec-Zone.ru › C++

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.

1) Элементы сравниваются с помощью заданной бинарной функции сравнения comp.
2) То же, что и (1), но использует r1 в качестве первого диапазона и r2 в качестве второго диапазона, как если бы ranges::begin(r1) использовалось как first1, ranges::end(r1) как last1, ranges::begin(r2) как first2, и ranges::end(r2) как last2.

Поведение является неопределённым, если целевой диапазон перекрывается с любым из входных диапазонов (входные диапазоны могут перекрываться друг с другом).

Эта функция объединения является стабильной, что означает, что для эквивалентных элементов в исходных двух диапазонах элементы из первого диапазона (сохраняя их исходный порядок) предшествуют элементам из второго диапазона (сохраняя их исходный порядок).

Функциональные сущности, описанные на этой странице, являются niebloids, то есть:

  • Явные списки шаблонных аргументов не могут быть указаны при вызове ни одного из них.
  • Ни один из них не виден для поиска зависимого от аргументов.
  • Когда любой из них найден обычным поиском без квалификатора как имя слева от оператора вызова функции, поиск зависимый от аргументов запрещен.

На практике они могут быть реализованы как объекты функций или с помощью специальных расширений компилятора.

Параметры

first1, last1 - первый входной отсортированный диапазон
first2, last2 - второй входной отсортированный диапазон
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 }

См. также

ranges::inplace_merge
(C++20)
объединяет два упорядоченных диапазона на месте
(niebloid)
ranges::is_sorted
(C++20)
проверяет, отсортирован ли диапазон в порядке возрастания
(niebloid)
ranges::set_union
(C++20)
вычисляет объединение двух множеств
(niebloid)
ranges::sort
(C++20)
сортирует диапазон в порядке возрастания
(niebloid)
ranges::stable_sort
(C++20)
сортирует диапазон элементов, сохраняя порядок между равными элементами
(niebloid)
merge
объединяет два отсортированных диапазона
(шаблонная функция)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/algorithm/ranges/merge

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API