Namespaces
Variants

std::ranges::inplace_merge

De es.cppreference.net
 
 
Biblioteca de algoritmos
Algoritmos restringidos y algoritmos sobre rangos (C++20)
Algoritmos restringidos, p. ej. ranges::copy, ranges::sort, ...
Operaciones de secuencia no modificadoras    
Operaciones por lotes
(C++17)
Operaciones de búsqueda
Operaciones de secuencia modificadoras
Operaciones de copia
(C++11)
(C++11)
Operaciones de intercambio
Operaciones de transformación
Operaciones de generación
Operaciones de eliminación
Operaciones de cambio de orden
(hasta C++17)(C++11)
(C++20)(C++20)
Operaciones de muestreo
(C++17)

Ordenamiento y operaciones relacionadas
Operaciones de particionamiento
(C++11)    

Operaciones de ordenamiento
Operaciones de búsqueda binaria
(en rangos particionados)
Operaciones de conjunto (en rangos ordenados)
Operaciones de mezcla (en rangos ordenados)
Operaciones de montículo
Operaciones de mínimo/máximo
(C++11)
(C++17)
Operaciones de comparación lexicográfica
Operaciones de permutación


 
Algoritmos restringidos
Todos los nombres en este menú pertenecen al espacio de nombres std::ranges
Operaciones de secuencia no modificadoras
Operaciones de secuencia modificadoras
Operaciones de particionamiento
Operaciones de ordenamiento
Operaciones de búsqueda binaria (en rangos ordenados)
       
       
Operaciones de conjunto (en rangos ordenados)
Operaciones de montículo
Operaciones de mínimo/máximo
       
       
Operaciones de permutación
Operaciones de plegado
Operaciones sobre almacenamiento no inicializado
Tipos de retorno
 
Definido en el encabezado <algorithm>
Firma de llamada
template< std::bidirectional_iterator I, std::sentinel_for<I> S,
          class Comp = ranges::less, class Proj = std::identity >
requires std::sortable<I, Comp, Proj>
    I inplace_merge( I first, I middle, S last,
                     Comp comp = {}, Proj proj = {} );
(1) (desde C++20)
(constexpr desde C++26)
template< ranges::bidirectional_range R, class Comp = ranges::less,
          class Proj = std::identity >
requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
ranges::borrowed_iterator_t<R>
    inplace_merge( R&& r, ranges::iterator_t<R> middle,
                   Comp comp = {}, Proj proj = {} );
(2) (desde C++20)
(constexpr desde C++26)

Fusiona dos rangos ordenados consecutivos [first, middle) y [middle, last) en un único rango ordenado [first, last).

Se dice que una secuencia está ordenada con respecto al comparador comp y la proyección proj si para cualquier iterador it que apunte a la secuencia y cualquier entero no negativo n tal que it + n sea un iterador válido apuntando a un elemento de la secuencia, std::invoke(comp, std::invoke(proj, *(it + n)), std::invoke(proj, *it))) evalúa a false.

Esta función de fusión es estable, lo que significa que para elementos equivalentes en los dos rangos originales, los elementos del primer rango (preservando su orden original) preceden a los elementos del segundo rango (preservando su orden original).

1) Los elementos se comparan usando la función de comparación binaria dada comp y el objeto de proyección proj, y los rangos deben estar ordenados con respecto a los mismos.
2) Igual que (1), pero usa r como el rango, como si usara ranges::begin(r) como first, y ranges::end(r) como last.

Las entidades similares a funciones descritas en esta página son objetos función de algoritmo (conocidos informalmente como niebloids), es decir:

Parámetros

first - inicio del primer rango ordenado
middle - fin del primer rango e inicio del segundo rango
last - fin del segundo rango ordenado
r - rango de elementos a fusionar in situ
comp - comparación a aplicar a los elementos proyectados
proj - proyección a aplicar a los elementos en el rango

Valor de retorno

Un iterador igual a last .

Complejidad

Exactamente N − 1 comparaciones, si hay disponible un búfer de memoria adicional, donde N = ranges:: distance ( first, last ) . De lo contrario, 𝓞(N•log(N)) comparaciones. Adicionalmente, el doble de proyecciones que comparaciones en ambos casos.

Notas

Esta función intenta asignar un búfer temporal. Si la asignación falla, se elige el algoritmo menos eficiente.

Macro de prueba de características Valor Estándar Característica
__cpp_lib_constexpr_algorithms 202306L (C++26) constexpr Ordenamiento estable

Implementación posible

Esta implementación solo muestra el algoritmo más lento utilizado cuando no hay memoria adicional disponible. Consulte también la implementación en MSVC STL y libstdc++ .

struct inplace_merge_fn
{
    template<std::bidirectional_iterator I, std::sentinel_for<I> S,
             class Comp = ranges::less, class Proj = std::identity>
    requires std::sortable<I, Comp, Proj>
    constexpr I operator()(I first, I middle, S last, Comp comp = {}, Proj proj = {}) const
    {
        I last_it = ranges::next(middle, last);
        inplace_merge_slow(first, middle, last_it,
                           ranges::distance(first, middle),
                           ranges::distance(middle, last_it),
                           std::ref(comp), std::ref(proj));
        return last_it;
    }
    template<ranges::bidirectional_range R, class Comp = ranges::less,
             class Proj = std::identity>
    requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
    constexpr ranges::borrowed_iterator_t<R>
        operator()(R&& r, ranges::iterator_t<R> middle,
                   Comp comp = {}, Proj proj = {}) const
    {
        return (*this)(ranges::begin(r), std::move(middle), ranges::end(r),
                       std::move(comp), std::move(proj));
    }
private:
    template<class I, class Comp, class Proj>
    static constexpr void inplace_merge_slow(I first, I middle, I last,
                                             std::iter_difference_t<I> n1,
                                             std::iter_difference_t<I> n2,
                                             Comp comp, Proj proj)
    {
        if (n1 == 0 || n2 == 0)
            return;
        if (n1 + n2 == 2 && comp(proj(*middle), proj(*first)))
        {
            ranges::iter_swap(first, middle);
            return;
        }
        I cut1 = first, cut2 = middle;
        std::iter_difference_t<I> d1{}, d2{};
        if (n1 > n2)
        {
            d1 = n1 / 2;
            ranges::advance(cut1, d1);
            cut2 = ranges::lower_bound(middle, last, *cut1,
                                       std::ref(comp), std::ref(proj));
            d2 = ranges::distance(middle, cut2);
        }
        else
        {
            d2 = n2 / 2;
            ranges::advance(cut2, d2);
            cut1 = ranges::upper_bound(first, middle, *cut2,
                                       std::ref(comp), std::ref(proj));
            d1 = ranges::distance(first, cut1);
        }
        I new_middle = ranges::rotate(cut1, middle, cut2);
        inplace_merge_slow(first, cut1, new_middle, d1, d2,
                           std::ref(comp), std::ref(proj));
        inplace_merge_slow(new_middle, cut2, last, n1 - d1, n2 - d2,
                           std::ref(comp), std::ref(proj));
    }
};
inline constexpr inplace_merge_fn inplace_merge {};

Ejemplo

#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()
{
    // demostración personalizada de merge-sort
    std::vector v{8, 2, 0, 4, 9, 8, 1, 7, 3};
    print(v, ": antes de ordenar");
    merge_sort(v.begin(), v.end());
    print(v, ": después de ordenar\n");
    // fusión con objeto de función de comparación y proyección
    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, ": antes de fusionar", middle - r.begin());
    std::ranges::inplace_merge(r, middle, comp, proj);
    print(r, ": después de fusionar");
}

Salida:

8 2 0 4 9 8 1 7 3 : antes de ordenar
0 1 2 3 4 7 8 8 9 : después de ordenar
(0,1) (0,2) (0,3) │ (1,1) (1,2) : antes de fusionar
(0,1) (1,1) (0,2) (1,2) (0,3) : después de fusionar

Véase también

fusiona dos rangos ordenados
(objeto función de algoritmo)
calcula la unión de dos conjuntos
(objeto función de algoritmo)
comprueba si un rango está ordenado
(objeto función de algoritmo)
ordena un rango de elementos
(objeto función de algoritmo)
fusiona dos rangos ordenados en el lugar
(plantilla de función)