Such- und Sortierverfahren, Laufzeit
Ein Telefonbuch einer Großstadt hat Hunderttausende Einträge. Du blätterst nicht Seite für Seite, sondern schlägst die Mitte auf, siehst, ob dein Name davor oder dahinter steht, und halbierst den Rest. Bei einer Million Einträgen bist du nach höchstens 20 Schritten am Ziel. Das geht nur, weil das Buch sortiert ist.
Du lernst, wie lineare und binäre Suche arbeiten, fünf Sortierverfahren und wie man ihre Laufzeit unabhängig vom Rechner beschreibt: mit der O-Notation und den Komplexitätsklassen.
Lineare und binäre Suche
Die lineare Suche prüft die Elemente der Reihe nach und braucht im schlechtesten Fall Vergleiche. Sie funktioniert in jeder Liste. Die binäre Suche verlangt eine sortierte Liste. Sie vergleicht mit dem mittleren Element und sucht nur in der Hälfte weiter, in der das Gesuchte liegen kann.
| Zeile | Einrückung | Anweisung |
|---|---|---|
| 1 | 0 | |
| 2 | 1 | |
| 3 | 1 | |
| 4 | 1 | |
| 5 | 2 | |
| 6 | 2 | |
| 7 | 3 | |
| 8 | 2 | |
| 9 | 3 | |
| 10 | 2 | |
| 11 | 3 | |
| 12 | 1 |
Jeder Durchlauf halbiert den Suchbereich: Aus Elementen werden höchstens , dann und so weiter. Für genügen 10 Durchläufe, für sind es 20.
Binäre Suche von Hand
Binäre Suche von Hand
Die Liste ist 3, 8, 12, 17, 21, 25, 30, 34 (Index 0 bis 7). Wie läuft und wie ?
Suche nach 25: links = 0, rechts = 7, mitte = 3, liste[3] = 17 ist kleiner als 25, also links = 4. Dann mitte = (4 + 7) // 2 = 5, liste[5] = 25. Rückgabe 5 nach 2 Durchläufen.
Suche nach 10:
| Durchlauf | links | rechts | mitte | liste[mitte] | Folge |
|---|---|---|---|---|---|
| 1 | 0 | 7 | 3 | 17 | 17 > 10, rechts = 2 |
| 2 | 0 | 2 | 1 | 8 | 8 < 10, links = 2 |
| 3 | 2 | 2 | 2 | 12 | 12 > 10, rechts = 1 |
Nun ist links = 2 größer als rechts = 1, die Schleife endet, und die Rückgabe ist -1. Die 10 steht nicht in der Liste.
Sortierverfahren und Stabilität
Alle Verfahren sortieren aufsteigend.
- Bubblesort vertauscht benachbarte Elemente, die falsch herum stehen, und schiebt so das größte nach hinten.
- Selectionsort sucht im unsortierten Teil das kleinste Element und tauscht es an den Anfang dieses Teils.
- Insertionsort fügt das nächste Element des unsortierten Teils an der richtigen Stelle in den sortierten Teil davor ein, wie Spielkarten auf der Hand.
- Mergesort teilt die Liste in zwei Hälften, sortiert jede Hälfte nach demselben Verfahren und mischt die beiden sortierten Hälften zu einer sortierten Liste.
- Quicksort wählt ein Pivot-Element, ordnet die kleineren Elemente links und die größeren rechts davon an und sortiert beide Seiten nach demselben Verfahren.
Bei Mergesort und Quicksort wendet sich das Verfahren auf kleinere Teillisten selbst an. Dieses Prinzip heißt Rekursion und kommt in der nächsten Lektion.
Ein Verfahren ist stabil, wenn Elemente mit gleichem Schlüssel ihre Reihenfolge behalten. Das zählt beim Sortieren nach mehreren Merkmalen: Wer erst nach Name und dann stabil nach Klasse sortiert, erhält die Namen innerhalb jeder Klasse alphabetisch. Selectionsort ist nicht stabil: Aus 2a, 2b, 1 wird 1, 2b, 2a.
Insertionsort von Hand
Insertionsort von Hand
Sortiere 5, 2, 9, 1, 7 mit Insertionsort. Ein Element wandert durch Vertauschen mit seinem linken Nachbarn nach vorn, solange dieser größer ist. Zähle Vergleiche und Vertauschungen.
Der sortierte Teil steht vorn, zuerst nur die 5.
- 2 ist kleiner als 5: vertauschen. Ergebnis 2, 5, 9, 1, 7 (1 Vergleich, 1 Vertauschung).
- 9 ist nicht kleiner als 5: bleibt (1 Vergleich).
- 1 ist kleiner als 9, 5 und 2 und wandert an den Anfang. Ergebnis 1, 2, 5, 9, 7 (3 Vergleiche, 3 Vertauschungen).
- 7 ist kleiner als 9: vertauschen, dann ist 7 nicht kleiner als 5. Ergebnis 1, 2, 5, 7, 9 (2 Vergleiche, 1 Vertauschung).
Insgesamt sind es 1 + 1 + 3 + 2 = 7 Vergleiche und 1 + 0 + 3 + 1 = 5 Vertauschungen. Jede Vertauschung beseitigt ein Paar, das falsch herum steht: (5, 2), (5, 1), (2, 1), (9, 1), (9, 7). Die Laufzeit hängt also von der Eingabe ab.
Laufzeit und O-Notation
Die Laufzeit zählt die Grundschritte (etwa Vergleiche) in Abhängigkeit von der Größe der Eingabe, nicht Sekunden. Sie hängt auch von der Eingabe ab: Man unterscheidet besten, mittleren und schlechtesten Fall. Für große zählt nur die Wachstumsart. Die O-Notation gibt eine obere Schranke an: heißt, dass es eine Konstante und ein gibt, sodass für alle höchstens beträgt. Konstante Faktoren und kleinere Summanden fallen weg.
Eine Laufzeit in O(n²) einordnen
Eine Laufzeit in O(n²) einordnen
Zeige für , dass gilt.
Wähle und . Für gilt . Daraus folgt . Probe bei : . Mit ginge es nicht, denn .
Komplexitätsklassen
Verfahren teilt man nach der Wachstumsart ihrer Laufzeit in Komplexitätsklassen ein: konstant, logarithmisch, linear, , quadratisch und exponentiell. Der Logarithmus hat hier die Basis 2. Eine andere Basis ändert nur den konstanten Faktor.
| n | |||||
|---|---|---|---|---|---|
| 10 | 3,3 | 10 | 33 | 100 | 1024 |
| 100 | 6,6 | 100 | 664 | 10000 | |
| 1000 | 10 | 1000 | 9966 | 1000000 |
Angenommen, ein Rechner schafft eine Milliarde Schritte pro Sekunde. Bei einer Million Elementen braucht ein Verfahren mit Schritten etwa 0,02 Sekunden, eines mit Schritten 1000 Sekunden, fast 17 Minuten. Bei Schritten und dauert es länger, als das Weltall alt ist.
Korrektheit, Effizienz und Speicherbedarf
Ein Sortierverfahren ist korrekt, wenn es für jede Eingabe terminiert und die Ausgabe aufsteigend geordnet und eine Umordnung der Eingabe ist. Man begründet das mit einer Schleifeninvariante, einer Aussage, die vor und nach jedem Durchlauf gilt. Beim Insertionsort lautet sie: Nach dem Durchlauf für Index sind die vorderen Elemente sortiert. Am Ende der Schleife folgt daraus die Korrektheit.
Effizienz meint Laufzeit und Speicherbedarf. Ein Verfahren mit nur konstantem Zusatzspeicher arbeitet am Platz. Jedes Verfahren, das nur durch Vergleiche sortiert, braucht im schlechtesten Fall mindestens etwa Vergleiche.
| Verfahren | bester Fall | schlechtester Fall | stabil | Zusatzspeicher |
|---|---|---|---|---|
| Bubblesort mit vorzeitigem Ende | ja | konstant | ||
| Selectionsort | nein | konstant | ||
| Insertionsort | ja | konstant | ||
| Mergesort | ja | etwa | ||
| Quicksort | nein | gering (Aufrufstapel) |
Mergesort ist auch im schlechtesten Fall schnell, braucht dafür aber Zusatzspeicher. Beim Quicksort tritt der schlechteste Fall ein, wenn das Pivot immer das kleinste Element ist.
Binäre Suche in jeder Liste
Binäre Suche in jeder Liste
„Die binäre Suche ist schneller, also nehme ich sie für jede Liste.“
Sie funktioniert nur in sortierten Listen. In 9, 2, 7, 4, 1 sucht sie die 1: Die Mitte ist 7, also geht es links weiter, dann ist die Mitte 9, und die Suche endet mit -1, obwohl die 1 vorhanden ist.
O(n²) ist immer langsamer als O(n log n)
O(n²) ist immer langsamer als O(n log n)
„Insertionsort ist quadratisch, Mergesort nicht, also ist Mergesort immer schneller.“
Die O-Notation sagt nur etwas über große und verschweigt konstante Faktoren. Bei kleinen oder fast sortierten Listen kann Insertionsort schneller sein, bei einer sortierten braucht er nur Vergleiche.
Zusammenfassung
Die lineare Suche braucht bis zu Vergleiche. Die binäre Suche braucht höchstens Durchläufe, verlangt aber eine sortierte Liste.
Bubblesort, Selectionsort und Insertionsort sind im schlechtesten Fall quadratisch, Mergesort ist immer , Quicksort im Mittel.
Stabil heißt: Gleiche Schlüssel behalten ihre Reihenfolge. Selectionsort und Quicksort sind nicht stabil.
Die Laufzeit zählt Schritte in Abhängigkeit von , getrennt nach bestem, mittlerem und schlechtestem Fall.
Die O-Notation ist eine obere Schranke ohne konstante Faktoren und kleinere Summanden. Klassen sind , , , und andere.
Korrektheit zeigt man mit einer Schleifeninvariante. Zeit und Speicher muss man gegeneinander abwägen.
Übungen
Die binäre Suche aus der Lektion durchsucht eine sortierte Liste mit 1000 Einträgen. Wie viele Schleifendurchläufe braucht sie im schlechtesten Fall?
Welches Verfahren ist in der Form aus der Lektion nicht stabil?
Ein Rechner schafft angenommen eine Milliarde Schritte pro Sekunde. Ein Verfahren braucht bei Elementen Schritte. Wie viele Sekunden dauert das?
Die Laufzeit ist . Welche ist die kleinste der folgenden Klassen, in der T liegt?
Du musst in einer Liste mit 100000 Einträgen 5000 Mal suchen. Vergleiche die Möglichkeiten, jedes Mal linear zu suchen oder die Liste einmal zu sortieren und dann binär zu suchen.