Halbieren und mischen
- Teilen:den Bereich
links … rechtsbeimittehalbieren — 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,jauf 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:
| Vergleich | a[i] | a[j] | übernommen | hilf |
|---|---|---|---|---|
| 1 | 9 | 12 | 9 | 9 |
| 2 | 17 | 12 | 12 | 9, 12 |
| 3 | 17 | 24 | 17 | 9, 12, 17 |
| 4 | 38 | 24 | 24 | 9, 12, 17, 24 |
| 5 | 38 | 45 | 38 | 9, 12, 17, 24, 38 |
| 6 | 52 | 45 | 45 | … 38, 45 |
| 7 | 52 | 71 | 52 | … 45, 52 |
| — | leer | 71 | 71 (Rest) | 9, 12, 17, 24, 38, 45, 52, 71 |
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.
| n | Eingabe | Vergleiche | n · log₂ n | Faktor bei 2n | Selectionsort |
|---|
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:Zwei Hälften sortieren, dann mischen: jeder Vergleich legt ein Element ab, also höchstens \(n - 1 < n\) Vergleiche.
\(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\).
Jede Ebene höchstens \(n\) Vergleiche; mit \(n = 2^k\) ist nach \(k = \log_2 n\) Ebenen jeder Bereich ein Element.
\(V(1) = 0\). Beispiel \(n = 1\,000\,000\): rund \(2\cdot10^{7}\) statt \(5\cdot10^{11}\) Vergleiche bei Selectionsort.
Mergesort: Hälften rekursiv sortieren, dann mischen · in jedem Fall höchstens \(n\cdot\log_2 n\) Vergleiche · Hilfsspeicher für \(n\) Elemente · stabil.
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.
