Informatik · Klasse 11–13 · aktualisiert
Quicksort einfach erklärt: Ablauf und Laufzeit
Du führst Quicksort Schritt für Schritt aus, begründest seine Korrektheit und erklärst, wie die Pivotwahl Laufzeit und Speicher beeinflusst.
0 von 11 Aufgaben gelöst
Kurz gesagt
Quicksort wählt ein Pivotelement und teilt die Liste in eine linke Teilliste mit kleineren und eine rechte mit größeren Elementen. Beide sortiert er auf dieselbe Weise weiter. Die Laufzeit hängt im Wesentlichen von der Pivotwahl ab: O(n·log(n)) im besten und durchschnittlichen Fall, O(n²) im schlechtesten.
Jede Suchmaschine, jede Highscore-Liste und jede Kontaktliste muss Daten ordnen. Quicksort ist ein schneller Weg dafür. Er teilt eine Liste immer wieder und sortiert die kleinen Teile. Wie gut das klappt, hängt an einer einzigen Entscheidung: Welches Element wählst du als Pivot?
Deine Lernziele
Hake ab, was du schon kannst. Löst du alle Aufgaben eines Abschnitts, hakt Mela das Ziel für dich ab.
3 Abschnitte
Quicksort sortiert eine Liste, indem er sie wiederholt teilt. Zuerst wählt er ein Element als Pivotelement aus. In den Beispielen hier ist das Pivot das Element ganz rechts.
Dann wird die Liste geteilt (man sagt auch: partitioniert). Alle Elemente, die kleiner als das Pivot sind, kommen in die linke Teilliste, alle größeren in die rechte. Elemente, die gleich dem Pivot sind, können sich beliebig auf die Teillisten verteilen. Die Elemente werden dabei nur innerhalb der Liste vertauscht und nicht in zusätzlichen Speicher kopiert.
So teilst du, wenn das Pivot ganz rechts steht: Der Index i startet links und sucht ein Element, das größer als das Pivot ist. Der Index j startet auf dem Element vor dem Pivot und sucht von rechts ein Element, das kleiner oder gleich dem Pivot ist. Die beiden gefundenen Elemente tauschst du. Danach suchen beide von ihren Positionen aus weiter, bis sich die Suchen treffen. Dort ist die Grenze zwischen den Teillisten.
Am Ende tauschst du das Pivot mit dem Element bei i, falls dieses Element größer als das Pivot ist. Sonst bleibt das Pivot, wo es ist. Dann steht das Pivot an der Trennstelle. Links davon stehen nur Elemente kleiner oder gleich dem Pivot, rechts nur größere.
Zum Schluss wendest du dasselbe Verfahren auf die linke und auf die rechte Teilliste an. Diese Selbstaufrufe heißen Rekursion. Das echte Beispiel unten sortiert Buchstaben alphabetisch. Das Zahlenbeispiel in der Musteraufgabe ist von uns ausgedacht.
Definition
Pivotelement
Das Pivotelement ist das Element, nach dem Quicksort die Liste teilt. Kleinere Elemente kommen in die linke Teilliste, größere in die rechte.
Beispiel: Die Buchstabenfolge „einbeispiel“ teilen
- 1Start: e i n b e i s p i e l. Das l ganz rechts ist das Pivot, i steht ganz links, j auf dem Element vor dem Pivot.
- 2Erste Suche: i bleibt auf dem n (größer als l), j auf dem e (kleiner oder gleich l). Nach dem Tausch: e i e b e i s p i n l
- 3Zweite Suche: i bleibt auf dem s, j auf dem i vor dem n. Nach dem Tausch: e i e b e i i p s n l
- 4Ende: Die Indizes treffen sich auf dem p. Das Pivot l wird mit dem p getauscht: e i e b e i i l s n p. Das l ist die Trennstelle.
Merke: Nach dem Teilen steht das Pivot an der Trennstelle. Links davon stehen nur Elemente kleiner oder gleich dem Pivot, rechts nur größere.
Teste dich
Quicksort arbeitet nach dem Prinzip „Teile und herrsche“: Er teilt die Liste und sortiert die Teile auf dieselbe Weise. Die Begründung, dass am Ende alles sortiert ist, besteht aus drei Schritten. Sie ist keine formale Beweisführung.
Erstens der Basisfall: Eine Teilliste der Länge eins oder null ist bereits sortiert. Dort bricht die Rekursion ab. Im Pseudocode wird nur geteilt, falls links < rechts gilt. Sonst passiert nichts.
Zweitens die Zerlegung: Nach der Aufteilung sind die Elemente der linken Liste kleiner oder gleich den Elementen der rechten Liste. Das Pivot steht an seiner endgültigen Position, kleinere Elemente davor, größere danach. Der Pseudocode ruft quicksort(links, teiler - 1) und quicksort(teiler + 1, rechts) auf. Wenn beide Teillisten in sich sortiert sind, ist die Gesamtliste sortiert, weil die Teillisten schon in der richtigen Position liegen.
Drittens muss die Rekursion enden. Das ist nur dann garantiert, wenn jede Teilliste mindestens um eins kürzer ist als die Gesamtliste. Das lässt sich zum Beispiel erreichen, indem das Pivot zwischen die Teillisten gesetzt wird und so zu keiner Teilliste gehört. Dann endet die Rekursion nach endlich vielen Schritten.
Ein Beispiel: Beim Sortieren der Buchstabenfolge „Quicksort“ entsteht nach dem ersten Teilen Qricksotu. Das t steht an der Trennstelle, rechts davon steht nur das u. Das ist ein einzelnes Element und damit sortiert. Quicksort ist im Allgemeinen nicht stabil: Gleiche Elemente können nach dem Sortieren in anderer Reihenfolge stehen.
Definition
Basisfall
Der Basisfall ist der Fall, in dem nichts mehr zu tun ist: Eine Teilliste der Länge eins oder null ist bereits sortiert, und die Rekursion bricht ab.
Merke: Quicksort sortiert korrekt, weil der Basisfall sortiert ist, die Zerlegung die Teillisten in die richtige Position bringt und jede Teilliste kürzer wird als die Gesamtliste.
Teste dich
Die Laufzeit von Quicksort hängt im Wesentlichen von der Wahl des Pivotelements ab. Die Schreibweise O(…) nennt, wie die Zahl der Vergleiche bei n Elementen ausfällt. n ist die Länge der Liste.
Im besten Fall wird das Pivot so gewählt, dass die beiden Teillisten etwa gleich groß sind. Dann gilt für die Laufzeit O(n·log(n)). Dieselbe Zeitkomplexität gilt ebenso für den durchschnittlichen Fall. Die Tiefe der Rekursion, also wie viele Selbstaufrufe ineinander stecken, liegt dann im Durchschnitt in O(log(n)).
Im schlechtesten Fall ist das Pivot stets das größte oder das kleinste Element der Liste. Das passiert zum Beispiel, wenn stets das letzte Element Pivot ist und die Liste schon sortiert vorliegt. Die Liste wird dann in jedem Rekursionsschritt nur um eins kleiner. Es werden O(n²) Vergleiche durchgeführt. Das kommt in der Praxis aber sehr selten vor.
Zum Speicher: Quicksort vertauscht die Elemente nur innerhalb der Liste. Für jede Rekursionsebene braucht er aber zusätzlichen Platz auf dem Stack (dem Stapel, auf dem die laufenden Aufrufe liegen). Auch dieser Speicherverbrauch hängt von der Pivotwahl und den Daten ab. Im günstigsten und durchschnittlichen Fall ist der Stapel O(log(n)) groß. Im ungünstigsten Fall ist die Zahl der Rekursionen nur durch die Listenlänge n beschränkt. Dann ist der Stapel O(n) groß, und bei langen Listen kann ein Stapelüberlauf entstehen.
Eine Gegenmaßnahme: Wird bei jeder Teilung die kürzere Teilliste rekursiv sortiert und die längere iterativ weiterverarbeitet (also mit einer Schleife statt mit einem weiteren Selbstaufruf), ist die Rekursionstiefe nicht größer als log(n).
| Fall | Stapel | Laufzeit |
|---|---|---|
| Bester und durchschnittlicher Fall | O(log(n)) | O(n·log(n)) |
| Schlechtester Fall | O(n) | O(n²) |
Beispiel: Wege, ein Pivot zu wählen
- 1Immer das erste, das letzte oder das mittlere Element: Dieser einfache Ansatz ist relativ ineffizient.
- 2Der Median dieser drei Elemente (der mittlere Wert unter ihnen): eine andere Möglichkeit.
- 3Ein zufälliges Element (randomisierter Quicksort): Dass in jedem Teilungsschritt der schlechteste Fall entsteht, ist extrem unwahrscheinlich.
- 4Ein zufälliges Pivot vermeidet systematische Probleme, die durch bestimmte Vorsortierungen im Zusammenspiel mit der Pivotwahl entstehen können.
Merke: Teilt das Pivot die Liste in etwa gleich große Teile, bleibt die Rekursion flach. Wird die Liste nur um eins kleiner, wird die Laufzeit O(n²) und der Stapel O(n) groß.
Teste dich
Alles auf einen Blick
Quicksort
Teilen
Das Pivot trennt die Liste in links kleiner oder gleich und rechts größer
Rekursion
Auf jede Teilliste wird dasselbe Verfahren angewandt
Basisfall
Eine Teilliste der Länge eins oder null ist schon sortiert
Ende der Rekursion
Jede Teilliste muss mindestens um eins kürzer sein als die Gesamtliste
Laufzeit
O(n·log(n)) im besten und durchschnittlichen Fall, O(n²) im schlechtesten
Speicher
Zusätzlicher Stack pro Rekursionsebene, im ungünstigsten Fall O(n)
Musteraufgabe · Schritt für Schritt
Die Folge 5 2 8 1 9 3 sortieren (ausgedachtes Beispiel)
- 1Das letzte Element ist das Pivot: 5 2 8 1 9 3, Pivot 3
- 2i startet auf der 5 (größer als 3). j startet auf der 9 und läuft nach links, bis ein Element kleiner oder gleich 3 kommt: j hält auf der 1.
- 3Tausch von 5 und 1: 1 2 8 5 9 3
- 4i läuft weiter und hält auf der 8 (größer als 3). j läuft von der 5 nach links und trifft i auf der 8. Die Suchen haben sich getroffen.
- 5Die 8 ist größer als das Pivot 3, also wird sie mit dem Pivot getauscht: 1 2 3 5 9 8. Die 3 ist die Trennstelle.
- 6Linke Teilliste 1 2: Pivot 2. Die 1 ist nicht größer als 2, das Pivot bleibt stehen. Die Teilliste ist sortiert: 1 2
- 7Rechte Teilliste 5 9 8: Pivot 8. Die 5 ist nicht größer, die 9 ist größer und wird mit dem Pivot getauscht: 5 8 9
- 8Alle Teillisten haben nun höchstens ein Element. Ergebnis: 1 2 3 5 8 9
Fehler finden
Prüfe die Aussagen zu Quicksort bei einer sortierten Liste In einer Zeile steckt ein Fehler. Tippe sie an.
Fehler in Zeile 4Eine sortierte Liste ist mit dem letzten Element als Pivot der schlechteste Fall. Richtig: Die Laufzeit liegt bei O(n²), nicht bei O(n·log(n)).
Lückentext
Wähl in jeder Lücke das passende Wort und prüf dann deine Antworten.
Nach dem Teilen stehen links vom Pivot nur Elemente kleiner oder gleich dem Pivot, rechts nur . Eine Teilliste der Länge ist bereits sortiert und beendet die Rekursion. Wird die Liste in jedem Schritt nur um eins kleiner, liegt die Laufzeit in .
Karteikasten
Erst selbst überlegen, dann umdrehen.
Übung mit Feedback