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 |
Mergesort: Teilen: Bereich bei mitte halbieren (ohne Vergleich). Herrschen: beide Hälften rekursiv sortieren. Zusammenführen: die sortierten Hälften mischen.
Basisfall: Ein Bereich mit höchstens einem Element (links ≥ rechts) ist schon sortiert.
Mischen: Zwei Zeiger auf die Anfänge; das kleinere Element kommt in die Hilfsreihung. Ist eine Hälfte leer, folgt der Rest der anderen ohne Vergleich.
Eigenschaften: Eine Hilfsreihung nötig (nicht in-place), stabil (bei Gleichheit zuerst das linke Element).
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 — stabil, Hilfsspeicher für \(n\) Elemente.
Aufwand: Jede Ebene kostet höchstens \(n\) Vergleiche, es gibt \(\log_2 n\) Ebenen; in jedem Fall gilt:
\(V(n)\le n\cdot\log_2 n\)
Vergleich: Verdoppelt man \(n\), steigen die Vergleiche auf gut das Doppelte, bei Selectionsort auf das Vierfache.
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.
