Spec-Zone.ru › C++

std::merge

Определено в заголовке <algorithm>
(1)
template< class InputIt1, class InputIt2, class OutputIt >
OutputIt merge( InputIt1 first1, InputIt1 last1,
                InputIt2 first2, InputIt2 last2,
                OutputIt d_first );
(до C++20)
template< class InputIt1, class InputIt2, class OutputIt >
constexpr OutputIt merge( InputIt1 first1, InputIt1 last1,
                          InputIt2 first2, InputIt2 last2,
                          OutputIt d_first );
(с 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)
(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 );
(до C++20)
template< class InputIt1, class InputIt2, class OutputIt, class Compare >
constexpr OutputIt merge( InputIt1 first1, InputIt1 last1,
                          InputIt2 first2, InputIt2 last2,
                          OutputIt d_first, Compare comp );
(с 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.

Последовательность считается отсортированной относительно компаратора comp , если для любого итератора it , указывающего на последовательность, и любого неотрицательного целого числа n такого, что it + n является допустимым итератором, указывающим на элемент последовательности, comp(*(it + n), *it) возвращает значение false.

1) Элементы сравниваются с использованием operator<.
3) Элементы сравниваются с использованием заданной двоичной функции сравнения comp.
2,4) То же, что (1,3), но выполняется в соответствии с policy. Эти перегрузки не участвуют в разрешении перегрузки, если

std::is_execution_policy_v<std::decay_t<ExecutionPolicy>> является true.

(до C++20)

std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> является true.

(с C++20)

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

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

Параметры

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

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

bool cmp(const Type1& a, const Type2& 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.

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

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

Сложность

При условии N как std::distance(first1, last1) + std::distance(first2, last2):

1) не более N - 1 сравнений с использованием operator<
2) O(N) сравнений с использованием operator<
3) не более N - 1 сравнений с использованием comp
4) O(N) сравнений с использованием comp

Исключения

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

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

Примечания

Этот алгоритм выполняет аналогичную задачу, что и 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 может производить меньше.

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

См. также реализации в 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);
}

Пример

#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <random>
#include <vector>
 
auto print = [](auto const rem, auto const& 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++.

DR Применено к Поведение, как опубликовано Правильное поведение
LWG 780 C++98 операция объединения не была определена определена

См. также

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

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

Spec-Zone.ru

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