Spec-Zone.ru › C++

std::merge

Объявлена в заголовочном файле <algorithm>
template< class InputIt1, class InputIt2, class OutputIt >
OutputIt merge( InputIt1 first1, InputIt1 last1,
                InputIt2 first2, InputIt2 last2,
                OutputIt d_first );
(1) (constexpr начиная с C++20)
template< class ExecutionPolicy,
          class ForwardIt1, class ForwardIt2, class ForwardIt3 >
ForwardIt3 merge( ExecutionPolicy&& policy,
                  ForwardIt1 first1, ForwardIt1 last1,
                  ForwardIt2 first2, ForwardIt2 last2,
                  ForwardIt3 d_first );
(2) (начиная с C++17)
template< class InputIt1, class InputIt2,
          class OutputIt, class Compare >
OutputIt merge( InputIt1 first1, InputIt1 last1,
                InputIt2 first2, InputIt2 last2,
                OutputIt d_first, Compare comp );
(3) (constexpr начиная с C++20)
template< class ExecutionPolicy,
          class ForwardIt1, class ForwardIt2,
          class ForwardIt3, class Compare >
ForwardIt3 merge( ExecutionPolicy&& policy,
                  ForwardIt1 first1, ForwardIt1 last1,
                  ForwardIt2 first2, ForwardIt2 last2,
                  ForwardIt3 d_first, Compare comp );
(4) (начиная с C++17)

Объединяет два отсортированных диапазона [first1, last1) и [first2, last2) в один отсортированный диапазон, начинающийся с d_first.

1) Если [first1, last1) или [first2, last2) не является отсортированным относительно operator<(до C++20)std::less{}(начиная с C++20), поведение не определено.
3) Если [first1, last1) или [first2, last2) не является отсортированным относительно comp, поведение не определено.
2,4) То же, что и (1,3), но выполняется согласно policy.
Эти перегрузки участвуют в разрешении перегрузки только в том случае, если значение следующего выражения равно true:

std::is_execution_policy_v<std::decay_t<ExecutionPolicy>>

(до C++20)

std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>>

(начиная с C++20)

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

Если выходной диапазон перекрывается с [first1, last1) или [first2, last2), поведение не определено.

Параметры

first1, last1 - пара итераторов, определяющая первый диапазон элементов для слияния
first2, last2 - пара итераторов, определяющая второй диапазон элементов для слияния
d_first - начало целевого диапазона
policy - политика выполнения, которая будет использоваться
comp - объект функции сравнения (то есть объект, удовлетворяющий требованиям Compare), который возвращает ​true, если первый аргумент меньше второго (то есть упорядочен перед ним).

Сигнатура функции сравнения должна быть эквивалентна следующей:

boolcmp(constType1&a,constType2&b);

Хотя в сигнатуре не обязательно использовать const&, функция не должна изменять переданные ей объекты и должна принимать любые значения типа (возможно, const) Type1 и Type2 независимо от категории значения (поэтому Type1& не допускается, как и Type1, кроме случаев, когда для Type1 перемещение эквивалентно копированию(начиная с C++11)).
Типы Type1 и Type2 должны быть такими, чтобы объекты типов InputIt1 и InputIt2 можно было разыменовать, а затем неявно преобразовать как в Type1, так и в Type2. ​

Требования к типам
-InputIt1, InputIt2 должен соответствовать требованиям LegacyInputIterator.
-ForwardIt1, ForwardIt2, ForwardIt3 должен соответствовать требованиям LegacyForwardIterator.
-OutputIt должен соответствовать требованиям LegacyOutputIterator.
-Compare должен соответствовать требованиям Compare.

Возвращаемое значение

Выходной итератор, указывающий на элемент после последнего скопированного элемента.

Сложность

Пусть \(\scriptsize N_1\)N1 — это std::distance(first1, last1), а \(\scriptsize N_2\)N2 — это std::distance(first2, last2):

1) Не более \(\scriptsize N_1+N_2-1\)N1+N2-1 сравнений с использованием operator<(до C++20)std::less{}(начиная с C++20).
2) \(\scriptsize O(N_1+N_2)\)O(N1+N2) сравнений с использованием operator<(до C++20)std::less{}(начиная с C++20).
3) Не более \(\scriptsize N_1+N_2-1\)N1+N2-1 вызовов функции сравнения comp.
4) \(\scriptsize O(N_1+N_2)\)O(N1+N2) вызовов функции сравнения comp.

Исключения

Перегрузки с параметром шаблона с именем ExecutionPolicy сообщают об ошибках следующим образом:

  • Если выполнение функции, вызванной в рамках алгоритма, выбрасывает исключение и ExecutionPolicy является одной из стандартных политик, вызывается std::terminate. Для любого другого ExecutionPolicy поведение определяется реализацией.
  • Если алгоритму не удаётся выделить память, выбрасывается std::bad_alloc.

Возможная реализация

См. также реализации в libstdc++ и libc++.

merge (1)
template<class InputIt1, class InputIt2, class OutputIt>
OutputIt merge(InputIt1 first1, InputIt1 last1,
               InputIt2 first2, InputIt2 last2,
               OutputIt d_first)
{
    for (; first1 != last1; ++d_first)
    {
        if (first2 == last2)
            return std::copy(first1, last1, d_first);
        
        if (*first2 < *first1)
        {
            *d_first = *first2;
            ++first2;
        }
        else
        {
            *d_first = *first1;
            ++first1;
        }
    }
    return std::copy(first2, last2, d_first);
}
merge (3)
template<class InputIt1, class InputIt2,
         class OutputIt, class Compare>
OutputIt merge(InputIt1 first1, InputIt1 last1,
               InputIt2 first2, InputIt2 last2,
               OutputIt d_first, Compare comp)
{
    for (; first1 != last1; ++d_first)
    {
        if (first2 == last2)
            return std::copy(first1, last1, d_first);
        
        if (comp(*first2, *first1))
        {
            *d_first = *first2;
            ++first2;
        }
        else
        {
            *d_first = *first1;
            ++first1;
        }
    }
    return std::copy(first2, last2, d_first);
}

Примечания

Этот алгоритм выполняет задачу, похожую на задачу std::set_union. Оба алгоритма принимают два отсортированных входных диапазона и создают отсортированный выходной диапазон из элементов обоих входных диапазонов. Различие между этими алгоритмами заключается в обработке значений из обоих входных диапазонов, которые сравниваются как эквивалентные (см. примечания к LessThanComparable). Если эквивалентные значения встречаются n раз в первом диапазоне и m раз во втором, std::merge выведет все n + m вхождений, тогда как std::set_union выведет только std::max(n, m) из них. Таким образом, std::merge выводит ровно std::distance(first1, last1) + std::distance(first2, last2) значений, а std::set_union может вывести меньше.

Пример

#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <random>
#include <vector>

auto print = [](const auto rem, const auto& v)
{
    std::cout << rem;
    std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';
};

int main()
{
    // fill the vectors with random numbers
    std::random_device rd;
    std::mt19937 mt(rd());
    std::uniform_int_distribution<> dis(0, 9);
    
    std::vector<int> v1(10), v2(10);
    std::generate(v1.begin(), v1.end(), std::bind(dis, std::ref(mt)));
    std::generate(v2.begin(), v2.end(), std::bind(dis, std::ref(mt)));
    
    print("Originally:\nv1: ", v1);
    print("v2: ", v2);
    
    std::sort(v1.begin(), v1.end());
    std::sort(v2.begin(), v2.end());
    
    print("After sorting:\nv1: ", v1);
    print("v2: ", v2);
    
    // merge
    std::vector<int> dst;
    std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(dst));
    
    print("After merging:\ndst: ", dst);
}

Возможный вывод:

Originally:
v1: 2 6 5 7 4 2 2 6 7 0
v2: 8 3 2 5 0 1 9 6 5 0
After sorting:
v1: 0 2 2 2 4 5 6 6 7 7
v2: 0 0 1 2 3 5 5 6 8 9
After merging:
dst: 0 0 0 1 2 2 2 2 3 4 5 5 5 6 6 6 7 7 8 9

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были применены задним числом к ранее опубликованным стандартам C++.

Отчёт об ошибке Применяется к Поведение согласно опубликованному стандарту Исправленное поведение
LWG 780 C++98 операция слияния не была определена определена

См. также

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

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

Spec-Zone.ru

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