Algorithmik und Programmierung
Ein Programm soll den Durchschnitt einer Notenliste berechnen. Es läuft ohne Fehlermeldung durch und zeigt 3,1, obwohl 2,6 richtig wäre. Der Rechner hat genau das getan, was im Programm steht. Der Fehler liegt in der Beschreibung des Vorgehens.
Du vertiefst, was du aus der Mittelstufe in Python kennst: Algorithmen genau beschreiben, Typumwandlungen, Kontrollstrukturen, Funktionen, Testen und ereignisgesteuerte Programme.
Algorithmus und seine Eigenschaften
Ein Algorithmus ist eine Vorschrift aus endlich vielen Einzelschritten, die jede Eingabe einer Problemklasse in eine Ausgabe überführt. Man verlangt meist:
- Eindeutigkeit und Ausführbarkeit: Jeder Schritt ist genau festgelegt und wirklich ausführbar.
- Endlichkeit: Die Vorschrift hat endliche Länge.
- Terminierung: Für jede zulässige Eingabe endet der Ablauf nach endlich vielen Schritten.
- Allgemeinheit: Er löst eine ganze Problemklasse, nicht nur eine einzelne Aufgabe.
- Determiniertheit: Gleiche Eingabe liefert gleiches Ergebnis.
Ein Algorithmus hängt nicht von einer Sprache ab. Ein Programm ist seine Umsetzung in einer Programmiersprache.
Variablen, Datentypen, Typumwandlung und Zeichenketten
Eine Variable hat einen Namen und verweist auf einen Wert mit einem Datentyp (, , , ). Bei der Zuweisung wird zuerst die rechte Seite berechnet und dann in x gespeichert. Eine Typumwandlung überführt einen Wert in einen anderen Typ:
| Ausdruck | Ergebnis | Art |
|---|---|---|
| 13 | explizit | |
| 2.5 | implizit, int wird zu float | |
| Laufzeitfehler (TypeError) | keine Umwandlung | |
| Laufzeitfehler (ValueError) | nicht umwandelbar |
Eine Zeichenkette ist eine Folge von Zeichen mit Index ab 0. Für gilt: ist 10, ist "I", ist "k", und die Teilkette ist "for" (Index 2 bis 4). Mit hängt man Zeichenketten aneinander. Sie sind unveränderlich: ist ein Fehler, man erzeugt eine neue Zeichenkette.
Kontrollstrukturen, Pseudocode und Struktogramm
Strukturierte Algorithmen bestehen aus Sequenz, Verzweigung und Wiederholung. Eine Schleife prüft ihre Bedingung vor dem Durchlauf (kopfgesteuert, läuft eventuell nie) oder danach (fußgesteuert, läuft mindestens einmal). Eine zählergesteuerte Schleife hat eine bekannte Zahl von Durchläufen. Pseudocode ist Text ohne feste Syntax. Ein Struktogramm (Nassi-Shneiderman) zeichnet dieselben Bausteine als ineinander liegende Rechtecke mit je einem Eingang und Ausgang.
| Baustein | Pseudocode | Struktogramm | Python |
|---|---|---|---|
| Sequenz | Anweisungen untereinander | Rechtecke übereinander | Zeilen untereinander |
| Verzweigung | falls B dann ... sonst ... | Rechteck mit Dreieck, Spalten „ja“ und „nein“ | ... |
| kopfgesteuert | solange B tue ... | Rahmen, Bedingung oben | |
| fußgesteuert | wiederhole ... bis B | Rahmen, Bedingung unten | und am Ende |
| zählergesteuert | für i von 1 bis n | Rahmen, Kopf „i = 1 bis n“ |
Eine Tracetabelle hält nach jedem Schritt die Werte aller Variablen fest. Mit ihr führst du einen Algorithmus von Hand aus und erkennst, was er berechnet und ob er terminiert.
Analyse mit Tracetabelle
Analyse mit Tracetabelle
Die Funktion wird mit aufgerufen. Was berechnet sie?
| Zeile | Einrückung | Anweisung |
|---|---|---|
| 1 | 0 | |
| 2 | 1 | |
| 3 | 1 | |
| 4 | 2 | |
| 5 | 2 | |
| 6 | 1 |
Die Tracetabelle zeigt die Werte nach jedem Durchlauf der Schleife:
| Zeitpunkt | n | s |
|---|---|---|
| vor der Schleife | 4729 | 0 |
| nach Durchlauf 1 | 472 | 9 |
| nach Durchlauf 2 | 47 | 11 |
| nach Durchlauf 3 | 4 | 18 |
| nach Durchlauf 4 | 0 | 22 |
Dann ist n > 0 falsch, und die Funktion gibt 22 zurück. Jeder Durchlauf addiert die letzte Ziffer () und schneidet sie ab (). Die Funktion berechnet die Quersumme: 4 + 7 + 2 + 9 = 22. Sie terminiert, weil n in jedem Durchlauf kleiner wird und nach so vielen Durchläufen 0 erreicht, wie n Ziffern hat. Spezifikation: Eingabe ist eine ganze Zahl , Ausgabe ihre Quersumme.
Funktionen, Parameter und Gültigkeitsbereich
Eine Funktion liefert mit einen Rückgabewert, eine Prozedur keinen (in Python automatisch ). Die Namen in sind formale Parameter, die Werte beim Aufruf aktuelle Parameter.
Eine lokale Variable (auch jeder Parameter) gilt nur während des Aufrufs und nur in der Funktion. Eine globale Variable steht außerhalb von Funktionen und ist überall lesbar. Weist eine Funktion einem Namen einen Wert zu, entsteht eine neue lokale Variable, auch bei gleichem globalem Namen. Nur mit ändert sie die globale. Besser sind Parameter und Rückgabewert.
Bei einem Wertparameter bekommt die Funktion eine Kopie, das Original bleibt unverändert. Bei einem Referenzparameter bekommt sie einen Verweis auf das Original, Änderungen sind danach außen sichtbar. Python übergibt immer Verweise. Bei Zahlen und Zeichenketten (unveränderlich) wirkt das wie ein Wertparameter, bei Listen (veränderlich) wie ein Referenzparameter.
Vom Problem zum getesteten Programm
Einen einfachen Algorithmus entwickelst du in vier Schritten. Die Spezifikation legt Eingabe, Ausgabe und Sonderfälle fest. Der Entwurf in Pseudocode oder Struktogramm klärt die Idee ohne Syntax. Die Implementierung setzt ihn in Python um. Das Testen prüft ihn gegen die Spezifikation.
Die Fehlerarten kennst du: Syntaxfehler verhindern den Start, Laufzeitfehler brechen den Ablauf ab, Semantikfehler liefern ein falsches Ergebnis. Auch eine Schleife, die nie endet, ist ein solcher Fehler: Die Terminierung ist verletzt. Ein Testfall besteht aus einer Eingabe und dem erwarteten Ergebnis, das du aus der Spezifikation bestimmst, nicht aus dem Programm. Wähle normale Fälle und Grenzfälle (leere Eingabe, kleinster und größter Wert). Testen kann Fehler zeigen, aber nicht beweisen, dass keiner mehr vorhanden ist.
Grafische Oberflächen und ereignisgesteuerte Programmierung
Eine grafische Benutzeroberfläche (GUI) besteht aus Bedienelementen wie Fenster, Beschriftung, Knopf und Textfeld. Das Programm läuft nicht von oben nach unten durch, sondern startet eine Ereignisschleife, die auf Ereignisse (Klick, Tastendruck) wartet. Für jedes Ereignis ruft sie eine vorher angemeldete Funktion auf, die Ereignisbehandlung. Diese Arbeitsweise heißt ereignisgesteuert.
Ein Zähler-Knopf
Ein Zähler-Knopf
Was passiert bei drei Klicks auf den Knopf, und was, wenn Zeile 4 fehlt?
| Zeile | Einrückung | Anweisung |
|---|---|---|
| 1 | 0 | |
| 2 | 0 | |
| 3 | 0 | |
| 4 | 1 | |
| 5 | 1 | |
| 6 | 1 | |
| 7 | 0 | |
| 8 | 0 | |
| 9 | 0 | |
| 10 | 0 | |
| 11 | 0 |
Zeile 10 meldet ohne Klammern als Ereignisbehandlung an: Die Funktion soll erst beim Klick laufen. Zeile 11 startet die Ereignisschleife. Bei jedem Klick wird zaehler um 1 größer, nach drei Klicks zeigt die Beschriftung 3. wandelt die Zahl in die Zeichenkette um, die erwartet. Fehlt Zeile 4, ist zaehler in lokal, und Zeile 5 bricht beim Lesen mit einem Laufzeitfehler (UnboundLocalError) ab.
Eine Funktion ändert die Variable des Aufrufers
Eine Funktion ändert die Variable des Aufrufers
„Mit in der Funktion habe ich die Variable a geändert, die ich übergeben habe.“
Der Parameter x ist lokal. Die Zuweisung bindet x an einen neuen Wert, a bleibt unverändert. Von außen ändern lässt sich nur ein veränderliches Objekt wie eine Liste, etwa mit . Sonst gibt man das Ergebnis mit zurück.
Alle Tests bestanden heißt fehlerfrei
Alle Tests bestanden heißt fehlerfrei
„Meine fünf Testfälle laufen durch, also ist das Programm richtig.“
Testen zeigt nur, dass bei den geprüften Eingaben das Richtige herauskommt. Ein Fehler in einem nicht geprüften Fall bleibt unbemerkt. Darum gehören Grenzfälle in jede Testreihe.
Zusammenfassung
Ein Algorithmus ist eindeutig, ausführbar, endlich beschrieben, terminiert und löst eine Problemklasse.
Typumwandlungen sind explizit (, ) oder implizit. Zeichenketten sind unveränderlich, der Index beginnt bei 0.
Sequenz, Verzweigung und Schleife lassen sich als Pseudocode, Struktogramm und Python darstellen. Die Tracetabelle zeigt, was ein Algorithmus berechnet.
Parameter und lokale Variablen gelten nur im Aufruf. Zahlen wirken wie Wertparameter, Listen wie Referenzparameter.
Spezifikation, Entwurf, Implementierung und Test folgen aufeinander. Testfälle kommen aus der Spezifikation und enthalten Grenzfälle.
Eine GUI wartet in einer Ereignisschleife und ruft für jedes Ereignis die angemeldete Ereignisbehandlung auf.
Übungen
Es läuft , danach für i von 1 bis 4 () die Anweisung . Welchen Wert hat a am Ende?
Was liefert der Ausdruck ?
Es gilt und . Die Funktion führt aus, die Funktion führt aus. Was sind a und b nach und ?
Eine Funktion startet mit n = 7 und wiederholt die Anweisung . Welche Eigenschaft eines Algorithmus ist verletzt?
Eine Funktion soll zählen, wie oft ein Zeichen in einer Zeichenkette vorkommt. Beschreibe den Algorithmus und nenne drei Testfälle mit erwartetem Ergebnis, darunter einen Grenzfall.