Lektion 1.2

Einfache Such- und Sortierverfahren

19 min Lesezeit

In deiner Tasche liegt ein Stapel Zettel ohne Ordnung, und du suchst einen bestimmten. Dir bleibt nur, die Zettel nacheinander anzusehen. Im Telefonbuch geht es leichter, denn die Namen sind sortiert. Auch ein Programm muss in Listen suchen: den größten Wert, eine bestimmte Zahl, eine passende Kombination.

Du lernst einige einfache Verfahren dafür und das Sortieren mit Bubblesort. Außerdem lernst du, wie man zwei Verfahren vergleicht: nicht nach der Uhr, sondern nach der Zahl der Schritte.

Definition

Summenbildung und Maximumsuche

Viele Algorithmen gehen ein Feld (in Python eine Liste) mit einer Schleife einmal von vorn nach hinten durch. Bei der Summenbildung startet die Variable summe\texttt{summe} bei 0, und jedes Element wird addiert. Teilt man die Summe durch die Anzahl der Elemente, erhält man den Mittelwert.

Die Maximumsuche findet das größte Element. Du merkst dir das bisher größte und ersetzt es, sobald ein größeres kommt. Der Startwert ist das erste Element, nicht 0, denn alle Zahlen könnten negativ sein.

ZeileEinrückungAnweisung
10summe = 0\texttt{summe = 0}
20maximum = zahlen[0]\texttt{maximum = zahlen[0]}
30for z in zahlen:\texttt{for z in zahlen:}
41summe = summe + z\texttt{summe = summe + z}
51if z > maximum:\texttt{if z > maximum:}
62maximum = z\texttt{maximum = z}
Beispiel

Summe und Maximum von Hand

Die Liste ist zahlen = [7, 3, 9, 4]\texttt{zahlen = [7, 3, 9, 4]}. Welche Werte haben summe\texttt{summe} und maximum\texttt{maximum} am Ende des obigen Programms?

Vor der Schleife gilt summe = 0 und maximum = 7 (das erste Element).

Durchlaufzsummemaximum
1777
23107
39199
44239

Im ersten Durchlauf ist 7 > 7 falsch, das Maximum bleibt. Im dritten ist 9 > 7 wahr, das Maximum wird 9. Ergebnis: Summe 23, Maximum 9. Der Mittelwert wäre 23 / 4 = 5,75.

Definition

Lineare Suche

Die lineare Suche prüft die Elemente der Reihe nach, bis sie das gesuchte findet. Sie gibt den Index des ersten Treffers zurück. Ist das Gesuchte nicht in der Liste, gibt sie -1 zurück, denn -1 ist kein möglicher Index. return\texttt{return} beendet die Funktion sofort.

ZeileEinrückungAnweisung
10def suche(zahlen, gesucht):\texttt{def suche(zahlen, gesucht):}
21for i in range(len(zahlen)):\texttt{for i in range(len(zahlen)):}
32if zahlen[i] == gesucht:\texttt{if zahlen[i] == gesucht:}
43return i\texttt{return i}
51return -1\texttt{return -1}

Sie funktioniert in jeder Liste, auch in einer ungeordneten. Im besten Fall steht das Gesuchte vorn und es genügt 1 Vergleich. Im schlechtesten Fall steht es ganz hinten oder fehlt, dann sind es so viele Vergleiche, wie die Liste Elemente hat.

Beispiel

Suchen in einer Liste

Was liefert suche([7, 3, 9, 4], 9)\texttt{suche([7, 3, 9, 4], 9)} und was suche([7, 3, 9, 4], 5)\texttt{suche([7, 3, 9, 4], 5)}? Wie viele Vergleiche gibt es jeweils?

Erster Aufruf: i = 0: 7 == 9 ist falsch. i = 1: 3 == 9 ist falsch. i = 2: 9 == 9 ist wahr, die Funktion gibt 2 zurück. Das waren 3 Vergleiche.

Zweiter Aufruf: Alle vier Vergleiche (7, 3, 9, 4 gegen 5) sind falsch. Die Schleife endet, und Zeile 5 gibt -1 zurück. Das waren 4 Vergleiche.

Definition

Erschöpfende Suche

Bei der erschöpfenden Suche erzeugt das Programm alle möglichen Lösungen der Reihe nach und prüft jede. Sie ist einfach und findet eine Lösung sicher, wenn es eine gibt. Sie kann aber lange dauern: Ein Zahlenschloss mit 3 Ziffern hat 10 mal 10 mal 10 = 1000 Einstellungen. Anders als bei der linearen Suche steht die Liste der Möglichkeiten nicht schon da, sondern wird beim Durchlaufen erzeugt, meist mit ineinander liegenden Schleifen.

Beispiel

Zwei Zahlen durchprobieren

Gesucht sind zwei ganze Zahlen von 1 bis 20 mit der Summe 20 und dem Produkt 91.

ZeileEinrückungAnweisung
10for a in range(1, 21):\texttt{for a in range(1, 21):}
21for b in range(1, 21):\texttt{for b in range(1, 21):}
32if a + b == 20 and a * b == 91:\texttt{if a + b == 20 and a * b == 91:}
43print(a, b)\texttt{print(a, b)}

range(1, 21)\texttt{range(1, 21)} liefert die Zahlen 1 bis 20. Die äußere Schleife wählt a, die innere durchläuft für jedes a alle b. Das sind 20 mal 20 = 400 Paare, und für jedes prüft Zeile 3 beide Bedingungen.

Die Ausgabe ist 7 13 und 13 7. Probe: 7 + 13 = 20 und 7 * 13 = 91.

Definition

Prinzip des Sortierens

Sortieren heißt, die Elemente eines Feldes nach einer Ordnung anzuordnen, zum Beispiel Zahlen aufsteigend. Sortierte Daten lassen sich leichter lesen und auswerten (Rangliste, Telefonbuch). Die einfachen Verfahren brauchen nur zwei Grundschritte: zwei Elemente vergleichen und zwei Elemente vertauschen.

Beim Vertauschen brauchst du eine Hilfsvariable. Würdest du a = b\texttt{a = b} und dann b = a\texttt{b = a} schreiben, wäre der alte Wert von a nach der ersten Zeile verloren.

Definition

Bubblesort

Bubblesort vergleicht in einem Durchlauf immer zwei Nachbarn und vertauscht sie, wenn der linke größer ist. Dabei wandert das größte Element nach rechts, wie eine Luftblase im Wasser nach oben. Danach wiederholt sich das mit dem Rest der Liste, der um ein Element kürzer ist, bis alles sortiert ist.

ZeileEinrückungAnweisung
10n = len(zahlen)\texttt{n = len(zahlen)}
20for runde in range(n - 1):\texttt{for runde in range(n - 1):}
31for i in range(n - 1 - runde):\texttt{for i in range(n - 1 - runde):}
42if zahlen[i] > zahlen[i + 1]:\texttt{if zahlen[i] > zahlen[i + 1]:}
53tausch = zahlen[i]\texttt{tausch = zahlen[i]}
63zahlen[i] = zahlen[i + 1]\texttt{zahlen[i] = zahlen[i + 1]}
73zahlen[i + 1] = tausch\texttt{zahlen[i + 1] = tausch}
Beispiel

Bubblesort von Hand

Sortiere die Liste 5, 2, 9, 1 aufsteigend mit Bubblesort. Wie viele Vergleiche und Vertauschungen gibt es?

Durchlauf 1 (3 Vergleiche): 5 > 2, tauschen: 2, 5, 9, 1. Dann 5 > 9 ist falsch. Dann 9 > 1, tauschen: 2, 5, 1, 9. Die 9 steht richtig.

Durchlauf 2 (2 Vergleiche): 2 > 5 ist falsch. Dann 5 > 1, tauschen: 2, 1, 5, 9.

Durchlauf 3 (1 Vergleich): 2 > 1, tauschen: 1, 2, 5, 9.

Insgesamt sind es 3 + 2 + 1 = 6 Vergleiche und 2 + 1 + 1 = 4 Vertauschungen.

Bubblesort Schritt für Schritt

Hier steht die Liste 5, 2, 9, 1 aus dem Beispiel. Klicke immer wieder auf den Knopf für den nächsten Schritt und beobachte, welche zwei Nachbarn verglichen werden und wann sie tauschen. Am Ende zeigen die Zähler "Vergleiche" 6 und "Vertauschungen" 4. Gib dann im Feld "Zahlen" die schon sortierte Liste 1, 2, 5, 9 ein und klicke auf "Übernehmen": Ohne Tausch endet das Verfahren schon nach einem Durchlauf mit 3 Vergleichen.

Definition

Effizienzvergleich von Algorithmen

Ein Algorithmus ist effizient, wenn er für eine Aufgabe wenige Schritte braucht. In Sekunden zu messen taugt schlecht, denn die Zeit hängt vom Rechner ab. Besser zählst du die Vergleiche in Abhängigkeit von der Zahl nn der Elemente.

Summenbildung und Maximumsuche brauchen nn Durchläufe: Doppelt so viele Elemente bedeuten doppelt so viele Schritte. Die lineare Suche braucht im schlechtesten Fall nn Vergleiche. Beim Bubblesort ohne vorzeitiges Ende gibt es (n−1)+(n−2)+⋯+1(n-1) + (n-2) + \dots + 1 Vergleiche. Für n=4n = 4 sind das 3+2+1=63 + 2 + 1 = 6, und die Formel liefert dasselbe:

nMaximumsucheBubblesort
101045
1001004950
10001000499500

Bei Bubblesort wächst der Aufwand viel schneller: Zehnmal so viele Elemente brauchen etwa hundertmal so viele Vergleiche. Wer 100 Zahlen sortiert, wartet nicht merklich. Bei einer Million Zahlen sind es etwa 500 Milliarden Vergleiche, und Bubblesort dauert sehr lange.

V(n)=n⋅(n−1)2V(n) = \frac{n \cdot (n - 1)}{2}
Häufige Fehler

Zu früh aufgeben bei der linearen Suche

In der Schleife steht nach dem if\texttt{if} ein else:\texttt{else:} mit return -1\texttt{return -1}. „So meldet die Funktion sofort, wenn ein Element nicht passt.“

Richtig ist

Dann endet die Funktion schon beim ersten Element, das nicht passt. Suchst du 9 in der Liste 7, 3, 9, 4, gibt sie sofort -1 zurück, obwohl die 9 drin steht. return -1\texttt{return -1} gehört hinter die Schleife, denn erst dort weißt du, dass kein Element gepasst hat.

Häufige Fehler

Ein Durchlauf sortiert alles

„Nach dem ersten Durchlauf von Bubblesort ist die Liste sortiert.“

Richtig ist

Nach einem Durchlauf steht nur das größte Element an seinem Platz. Aus 5, 2, 9, 1 wird 2, 5, 1, 9, und das ist noch nicht sortiert. Es braucht weitere Durchläufe.

Zusammenfassung

  • Summenbildung und Maximumsuche gehen die Liste einmal durch. Das Maximum startet mit dem ersten Element.

  • Die lineare Suche prüft Element für Element und gibt den Index des ersten Treffers oder -1 zurück. Im schlechtesten Fall braucht sie n Vergleiche.

  • Die erschöpfende Suche probiert alle Möglichkeiten durch. Sie findet sicher eine Lösung, kann aber sehr viele Schritte brauchen.

  • Einfache Sortierverfahren nutzen nur Vergleichen und Vertauschen. Vertauschen braucht eine Hilfsvariable.

  • Bubblesort vertauscht in jedem Durchlauf Nachbarn, die falsch herum stehen, und schiebt so das größte Element nach rechts. Dafür sind bis zu n(n-1)/2 Vergleiche nötig.

  • Effizienz misst man in Schritten abhängig von n, nicht in Sekunden.

Übungen

Aufgabe 1Numerisch

Wie viele Vergleiche macht der Bubblesort aus der Lektion (ohne vorzeitiges Ende) bei 8 Zahlen?

Aufgabe 2Numerisch

Das Programm für Summe und Maximum läuft über die Liste 6, 11, 4, 9. Welchen Wert hat summe nach dem dritten Durchlauf?

Aufgabe 3Multiple Choice

Was gibt suche([8, 3, 8, 1], 8)\texttt{suche([8, 3, 8, 1], 8)} zurück?

Aufgabe 4Multiple Choice

Die Zahl der Elemente verdoppelt sich. Wie ändert sich ungefähr die Zahl der Vergleiche bei der Maximumsuche und beim Bubblesort?

Aufgabe 5Numerisch

Ein Fahrradschloss hat 4 Ziffernräder mit den Ziffern 0 bis 9. Wie viele Einstellungen muss man bei der erschöpfenden Suche im schlechtesten Fall durchprobieren? Schreibe die Zahl ohne Punkt.

Aufgabe 6Freitext

Sortiere die Liste 4, 3, 1 mit Bubblesort. Gib die Liste nach jedem Durchlauf an und nenne die Zahl der Vertauschungen.