MINT lernen

Mergesort

Zwei sortierte Stapel zu einem zu mischen ist leicht — und genau daraus baut Mergesort ein schnelles Sortierverfahren.

1

Halbieren und mischen

  • Teilen:den Bereich links … rechts bei mitte halbieren — ohne Vergleich.
  • Herrschen:beide Hälften rekursiv mit Mergesort sortieren.
  • Zusammenführen:die zwei sortierten Hälften zu einer sortierten Folge mischen (engl. merge).
  • Basisfall:Abbruchbedingung: ein Bereich mit höchstens einem Element (links ≥ rechts) ist schon sortiert.
  • Mischen:zwei Zeiger i, j auf die Anfänge; das kleinere Element in die Hilfsreihung, dessen Zeiger rückt vor. Ist eine Hälfte leer, kommt der Rest der anderen ohne Vergleich dazu.
  • Speicher:eine Hilfsreihung für den gemischten Bereich — Mergesort sortiert nicht in-place.
  • Stabil:bei Gleichheit wird zuerst das linke Element genommen (<=).
static void mergesort(int[] a, int links, int rechts) {
    if (links < rechts) {                        // sonst: Basisfall, 0 oder 1 Element
        int mitte = (links + rechts) / 2;
        mergesort(a, links, mitte);              // linke Hälfte sortieren
        mergesort(a, mitte + 1, rechts);         // rechte Hälfte sortieren
        mische(a, links, mitte, rechts);         // beide Hälften mischen
    }
}

static void mische(int[] a, int links, int mitte, int rechts) {
    int[] hilf = new int[rechts - links + 1];
    int i = links, j = mitte + 1, k = 0;
    while (i <= mitte && j <= rechts) {
        if (a[i] <= a[j]) {                      // <= hält gleiche Werte stabil
            hilf[k] = a[i];
            i++;
        } else {
            hilf[k] = a[j];
            j++;
        }
        k++;
    }
    while (i <= mitte) {                         // Rest der linken Hälfte
        hilf[k] = a[i];
        i++;
        k++;
    }
    while (j <= rechts) {                        // Rest der rechten Hälfte
        hilf[k] = a[j];
        j++;
        k++;
    }
    for (k = 0; k < hilf.length; k++) {          // zurückkopieren
        a[links + k] = hilf[k];
    }
}

Beispiel a = {52, 17, 38, 9, 71, 24, 45, 12}: Nach den beiden rekursiven Aufrufen steht links 9, 17, 38, 52, rechts 12, 24, 45, 71. Der letzte Aufruf mische(a, 0, 3, 7) arbeitet so:

Vergleicha[i]a[j]übernommenhilf
191299
21712129, 12
31724179, 12, 17
43824249, 12, 17, 24
53845389, 12, 17, 24, 38
6524545… 38, 45
7527152… 45, 52
—leer7171 (Rest)9, 12, 17, 24, 38, 45, 52, 71
2

Vergleiche messen

Die acht Werte sind schon in Einzelelemente zerlegt. Mische Ebene für Ebene: Klicke die kleinere der beiden hervorgehobenen Karten an (oder ← für die linke, → für die rechte Karte). Der Zähler rechts misst die Vergleiche jeder Ebene. Starte danach mit „Messreihe“ die Messung für größere n.

Mischen mit Vergleichszähler

Messtabelle Mergesort
nEingabeVergleichen · log₂ nFaktor bei 2nSelectionsort

Halte fest: Jede Ebene kostet höchstens n Vergleiche, und es gibt log₂ n Ebenen. Verdoppelt man n, steigen die Vergleiche nur auf gut das Doppelte — bei Selectionsort auf das Vierfache.

Herleitung:
\(V(n) \le 2\,V\!\left(\tfrac{n}{2}\right) + n\)
Ansatz

Zwei Hälften sortieren, dann mischen: jeder Vergleich legt ein Element ab, also höchstens \(n - 1 < n\) Vergleiche.

\(\le 4\,V\!\left(\tfrac{n}{4}\right) + 2n\)
einsetzen

\(V\!\left(\frac{n}{2}\right) \le 2\,V\!\left(\frac{n}{4}\right) + \frac{n}{2}\) eingesetzt — die zweite Ebene kostet wieder höchstens \(n\).

\(\le 2^k\,V\!\left(\tfrac{n}{2^k}\right) + k\cdot n\)
\(k\)-mal

Jede Ebene höchstens \(n\) Vergleiche; mit \(n = 2^k\) ist nach \(k = \log_2 n\) Ebenen jeder Bereich ein Element.

\(V(n) \le n\cdot\log_2 n\)
Ergebnis

\(V(1) = 0\). Beispiel \(n = 1\,000\,000\): rund \(2\cdot10^{7}\) statt \(5\cdot10^{11}\) Vergleiche bei Selectionsort.

Merke

Mergesort: Hälften rekursiv sortieren, dann mischen · in jedem Fall höchstens \(n\cdot\log_2 n\) Vergleiche · Hilfsspeicher für \(n\) Elemente · stabil.

3

Allgemeine Hinweise

Den Rest nicht vergessen

Die Hauptschleife endet, sobald eine Hälfte leer ist. Fehlen die beiden Rest-Schleifen, gehen die übrigen Elemente der anderen Hälfte verloren — die Reihung enthält danach alte Werte.

Mischen zählen

Bei zwei Hälften der Längen \(p\) und \(q\) braucht das Mischen mindestens \(\min(p, q)\) und höchstens \(p + q - 1\) Vergleiche — wenige, wenn eine Hälfte komplett kleiner ist.

Schnell, aber nicht sparsam

Mergesort braucht Platz für eine zweite Reihung. Die Rekursionstiefe bleibt dagegen klein: nur etwa \(\log_2 n\) Aufrufe liegen gleichzeitig auf dem Aufrufstapel.

Videos