Namespaces
Variants

std::ranges::inplace_merge

Von de.cppreference.net
 
 
Algorithmenbibliothek
Eingeschränkte Algorithmen und Algorithmen auf Bereichen (C++20)
Eingeschränkte Algorithmen, z.B. ranges::copy, ranges::sort, ...
Nicht modifizierende Sequenzoperationen    
Stapeloperationen
(C++17)
Suchoperationen
Modifizierende Sequenzoperationen
Kopieroperationen
(C++11)
(C++11)
Tauschoperationen
Transformationsoperationen
Erzeugungsoperationen
Entfernungsoperationen
Reihenfolgeänderungsoperationen
(bis C++17)(C++11)
(C++20)(C++20)
Stichprobenoperationen
(C++17)

Sortier- und verwandte Operationen
Partitionierungsoperationen
(C++11)    

Sortieroperationen
Binäre Suchoperationen
(auf partitionierten Bereichen)
Mengenoperationen (auf sortierten Bereichen)
Mischoperationen (auf sortierten Bereichen)
Heap-Operationen
Minimum/Maximum-Operationen
(C++11)
(C++17)
Lexikografische Vergleichsoperationen
Permutationsoperationen


 
Eingeschränkte Algorithmen
Alle Namen in diesem Menü gehören zum Namensraum std::ranges
Nicht modifizierende Sequenzoperationen
Modifizierende Sequenzoperationen
Partitionierungsoperationen
Sortieroperationen
Binäre Suchoperationen (auf sortierten Bereichen)
       
       
Mengenoperationen (auf sortierten Bereichen)
Heap-Operationen
Minimum/Maximum-Operationen
       
       
Permutationsoperationen
Faltungsoperationen
Numerikoperationen
(C++23)            
Operationen auf nicht initialisiertem Speicher
Rückgabetypen
 
Definiert in Header <algorithm>
Aufrufsignatur
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) (seit C++20)
(constexpr seit 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) (seit C++20)
(constexpr seit C++26)

Führt zwei aufeinanderfolgende sortierte Bereiche [first, middle) und [middle, last) in einen sortierten Bereich [first, last) zusammen.

Eine Sequenz heißt in Bezug auf den Komparator sortiert comp und die Projektion proj sortiert, wenn für jeden Iterator it, der auf die Sequenz zeigt, und jede nicht-negative ganze Zahl n, so dass it + n ein gültiger Iterator ist, der auf ein Element der Sequenz zeigt, std::invoke(comp, std::invoke(proj, *(it + n)), std::invoke(proj, *it))) zu false ausgewertet wird.

Diese Zusammenführungsfunktion ist stabil, was bedeutet, dass für äquivalente Elemente in den beiden ursprünglichen Bereichen die Elemente aus dem ersten Bereich (unter Beibehaltung ihrer ursprünglichen Reihenfolge) vor den Elementen aus dem zweiten Bereich (unter Beibehaltung ihrer ursprünglichen Reihenfolge) stehen.

1) Elemente werden unter Verwendung der gegebenen binären Vergleichsfunktion comp und des Projektionsobjekts proj verglichen, und die Bereiche müssen in Bezug auf dieselben sortiert sein.
2) Gleich (1), verwendet aber r als Bereich, als ob ranges::begin(r) als first und ranges::end(r) als last verwendet würden.

Die auf dieser Seite beschriebenen funktionsähnlichen Entitäten sind Algorithmus-Funktionsobjekte (informell als Niebloids bekannt), das heißt:

Parameter

first - der Anfang des ersten sortierten Bereichs
middle - das Ende des ersten Bereichs und der Anfang des zweiten Bereichs
last - das Ende des zweiten sortierten Bereichs
r - der Bereich der Elemente, die in-place zusammengeführt werden sollen
comp - Vergleich, der auf die projizierten Elemente angewendet wird
proj - Projektion, die auf die Elemente im Bereich angewendet wird

Rückgabewert

Ein Iterator gleich last .

Komplexität

Genau N − 1 Vergleiche, wenn ein zusätzlicher Speicherpuffer verfügbar ist, wobei N = ranges:: distance ( first, last ) . Andernfalls 𝓞(N•log(N)) Vergleiche. Zusätzlich in beiden Fällen doppelt so viele Projektionen wie Vergleiche.

Hinweise

Diese Funktion versucht, einen temporären Puffer zu allozieren. Wenn die Allokation fehlschlägt, wird der weniger effiziente Algorithmus gewählt.

Feature-Test Makro Wert Std Funktion
__cpp_lib_constexpr_algorithms 202306L (C++26) constexpr stabile Sortierung

Mögliche Implementierung

Diese Implementierung zeigt nur den langsameren Algorithmus, der verwendet wird, wenn kein zusätzlicher Speicher verfügbar ist. Siehe auch die Implementierung in MSVC STL und 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 {};

Beispiel

#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()
{
    // benutzerdefinierte Merge-Sort-Demo
    std::vector v{8, 2, 0, 4, 9, 8, 1, 7, 3};
    print(v, ": vor der Sortierung");
    merge_sort(v.begin(), v.end());
    print(v, ": nach der Sortierung\n");
    // Zusammenführen mit Vergleichsfunktionsobjekt und Projektion
    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, ": vor dem Zusammenführen", middle - r.begin());
    std::ranges::inplace_merge(r, middle, comp, proj);
    print(r, ": nach dem Zusammenführen");
}

Ausgabe:

8 2 0 4 9 8 1 7 3 : vor der Sortierung
0 1 2 3 4 7 8 8 9 : nach der Sortierung
(0,1) (0,2) (0,3) │ (1,1) (1,2) : vor dem Zusammenführen
(0,1) (1,1) (0,2) (1,2) (0,3) : nach dem Zusammenführen

Siehe auch

führt zwei sortierte Bereiche zusammen
(Algorithmus-Funktionsobjekt)
berechnet die Vereinigung zweier Mengen
(Algorithmus-Funktionsobjekt)
prüft, ob ein Bereich sortiert ist
(Algorithmus-Funktionsobjekt)
sortiert einen Bereich von Elementen
(Algorithmus-Funktionsobjekt)
führt zwei geordnete Bereiche in-place zusammen
(Funktionsvorlage)