Michael Fothe, Jena: (15. März 2004) Rekursion – ein Thema für den Informatikunterricht Hätte es im Mittelalter Rechenanlagen gegeben, dann wären bestimmt einige Programmierer wegen Ketzerei von andersgesinnten Kollegen auf dem Scheiterhaufen verbrannt worden. S. GILL (1960) 1 Einführung In der fachdidaktischen Literatur der letzten zehn Jahre wird das Thema Rekursion unterschiedlich gewichtet. WAGENKNECHT (1994) befasst sich unter Anwendung der Programmiersprache Scheme detailliert mit dem Thema. BAUMANN (1996) setzt sich mit den Möglichkeiten der Rekursion auseinander. RECHENBERG (1997) betrachtet die Rekursion, weil zu speziell, als in der Schulinformatik eher verzichtbar. HUBWIESER (2000) geht auf sie nicht näher ein. Bei SCHUBERT&SCHWILL (2004) ist Rekursion bei der fundamentalen Idee Algorithmisierung aufgeführt (S. 96). Das Ziel dieser Arbeit ist eine Positionsbestimmung innerhalb dieser Bandbreite. Die Frage, ob das Thema Rekursion in einen zeitgemäßen Informatikunterricht an allgemein bildenden Schulen gehört, wird aus zwei Gründen bejaht: Rekursion spielt in Theorie und Praxis der Informatik eine wesentliche Rolle (vgl. Sprachdefinitionen von Programmiersprachen, Algorithmen zur Verarbeitung von Listen und Syntaxanalyse mittels rekursiven Abstiegs) und es ist Aufgabe von Schule, frühzeitig in wichtige Denk- und Arbeitsweisen einzuführen. Die Frage wird im Resümee noch einmal aufgegriffen werden. In dieser Arbeit geht es um Unterrichtsziele, Beispiele und methodisches Herangehen. Dazu werden Erfahrungen, die der Autor im eigenen Unterricht in den Klassenstufen 9-12 und in der Thüringer Lehrerfortbildung gewonnen hat, theoretisch systematisierend aufgearbeitet. Nachfolgend wird Rekursion nicht als etwas Natürliches dargestellt. Nur wenige Beispiele für Endrekursion werden angegeben. Baumstrukturen und die Äquivalenz von Iteration und Rekursion werden thematisiert. In diesen Punkten besteht Übereinstimmung mit RECHENBERG (1997). 2 Zugänge zur Rekursion In diesem Abschnitt werden Informatikunterricht skizziert. sechs Zugänge zur Rekursion für den 2.1 Zugang über Sprachbeschreibungen Die Syntax von Programmiersprachen wird häufig auf rekursive Art angegeben. Damit wird eine kompakte Beschreibung erreicht. Ein erstes Beispiel ist die syntaktische Definition von Anweisung in der Programmiersprache Java, die nachfolgend auszugsweise angegeben ist. Die Definition erfolgt mithilfe der EBNF. Anweisung = … ( … | “if“ “(“ Ausdruck “)“ Anweisung [ “else“ Anweisung ] | “while“ “(“ Ausdruck “)“ Anweisung | “return“ [ Ausdruck ] “;“ | … ). Das zu definierende Nichtterminalsymbol Anweisung ist mehrfach auf der rechten Seite der Definition angegeben, d. h. bei der Definition von Anweisung wird Anweisung verwendet. Ein zweites Beispiel ist die Syntax der Ausdrücke in der Programmiersprache Oberon-2: Relation = “=“ | “#“ | “< “ | “<= “ | “>“ | “>=“ | “IN“ | “IS“. AddOperator = “+“ | “-“ | “OR“. MulOperator = “*“ | “/“ | “DIV“ | “MOD“ | “&“. Ausdruck = EinfacherAusdruck [ Relation EinfacherAusdruck ]. EinfacherAusdruck = [ “+“ | “-“ ] Term { AddOperator Term }. Term = Faktor { MulOperator Faktor }. Faktor = Zahl | ZeichenKonstante | Zeichenkette | NIL | Menge | Bezeichner [ AktuelleParameter ] | “(“ Ausdruck “)“ | “~“ Faktor. Der syntaktische Aufbau eines Ausdrucks wird durch ein System von Nichtterminalsymbolen rekursiv beschrieben (Ausdruck, EinfacherAusdruck, Term und Faktor). Ein Faktor kann z. B. eine Zahl, ein Variablenbezeichner oder – und damit wird die Rekursion deutlich – wieder ein Ausdruck (eingeschlossen in runde Klammern) sein. Nach der Beschreibung stellen z. B. die Zeichenfolgen 2*a+b=c, 1.0-(x-1.0)/(y-1.0) und a+b*(c+d*(e+f*(g+h*i))) syntaktisch korrekte Ausdrücke dar. Die Schülerinnen und Schüler sollen in der Lage sein, aus den Sprachbeschreibungen syntaktisch korrekte Zeichenfolgen zu bilden und die Korrektheit einer gegebenen Zeichenfolge zu überprüfen. Ein drittes Beispiel ist die „Sprache der Bäume“, bei der mithilfe von grafischen Terminal- und Nichtterminalsymbolen definiert wird, was unter einem binären Baum verstanden wird (vgl. NIEVERGELT&HINRICHS, S. 46 ff.). 2.2 Zugang über mathematische Kurven Ein Beispiel sind die rekursiven Hilbert-Kurven. H1 H2 H3 Im Unterricht können die Hilbert-Kurven H1, H2 und H3 vorgegeben werden. Ausgehend von der elementaren Hilbert-Kurve H1 werden die Konstruktion von H2 aus H1 und von H3 aus H2 nachvollzogen. Die Schülerinnen und Schüler erkennen, dass jeweils vier Hilbert-Kurven Hk zur Hilbert-Kurve Hk+1 zusammengesetzt werden. Die vier Hilbert-Kurven werden in die jeweils gleiche Position zueinander gebracht und mit Verbindungsstrecken, die in den Abbildungen aus Verständnisgründen hervorgehoben sind, verbunden. Im Unterricht kann auch nur die Hilbert-Kurve H3 vorgegeben werden. Dann wird analysiert, dass die Hilbert-Kurve H3 aus vier HilbertKurven H2 und dass die Hilbert-Kurve H2 aus vier Hilbert-Kurven H1 besteht. Weitere mathematische Kurven, die im Unterricht diskutiert werden können, sind z. B. die Sierpinski-Kurven, die Schneeflockenkurven und der Baum des Pythagoras (vgl. HEYDERHOFF, S. 14-20). 2.3 Zugang über Bilder Das „Bild im Bild“ beim Fernsehen verdeutlicht Wiederholung mit Rekursion. Die Zeichnung von M. C. Escher „Zeichnende Hände“ (1948) symbolisiert indirekte Rekursion, bei der sich zwei Unterprogramme wechselseitig aufrufen. Auch Phänomene mit Spiegeln werden mitunter der Rekursion zugeordnet (z. B. Aufenthalt zwischen zwei parallelen Spiegelflächen oder Kaleidoskope). Matroschkas sind eine schöne Illustration von Rekursion. 2.4 Zugang über Begriffsdefinitionen Die Definition wichtiger informatischer Begriffe erfolgt auf rekursive Art. Ein erstes Beispiel ist der Begriff Liste (vgl. z. B. FOTHE (2002)). Ein zweites Beispiel ist die Definition eines binären Baumes: Ein binärer Baum besteht aus einem Element (der Wurzel) und zwei binären Bäumen (dem linken und dem rechten Teilbaum) oder es ist der leere binäre Baum. Ein binärer Baum besteht aus endlich vielen Elementen. Die Schülerinnen und Schüler sollen sich mit der Definition aktiv auseinander setzen. Eine mögliche Aufgabe ist das Begründen, dass die nachfolgende Zeichnung einen binären Baum darstellt: A B D C E F G H Dabei wäre herauszuarbeiten, dass jeder Knoten, so z. B. auch E und F, zwei Teilbäume besitzt. Bei E sind beide Teilbäume leer, bei F ist nur der linke Teilbaum leer. Die Schülerinnen und Schüler sollen korrekte binäre Bäume angeben können. 2.5 Zugang über Texte In natürlichen Sprachen lassen sich Strukturen finden, mit denen sich VorErfahrungen zur Rekursion gewinnen lassen. Der Satz „Dass dieser Wurm an Würmern litt, die wiederum an Würmern litten…“ (Joachim Ringelnatz) und die Ankündigung „Ich pflege jedem Sonntagskind, das sich zu mir zu finden weiß, drei Wünsche zu gewähren. Die ersten zwei sind frei, den dritten kann ich verweigern, wenn er töricht ist.“ (Wilhelm Hauff: Das kalte Herz) illustrieren einen Spezialfall der Rekursion, die Endrekursion, sofern der dritte Wunsch wieder drei Wünsche sind. Ein weiteres Beispiel sind Schachtelsätze, wie ein Eintrag in einem Lokalanzeiger. Derjenige der den Täter der den Pfahl der an der Brücke die an dem Weg der nach Jena führt liegt steht umgeworfen hat anzeigt erhält eine Belohnung. Die Strukturierung kann mit Kommas erfolgen: Derjenige, der den Täter, der den Pfahl, der an der Brücke, die an dem Weg, der nach Jena führt, liegt, steht, umgeworfen hat, anzeigt, erhält eine Belohnung. Möglich ist auch eine Strukturierung durch Ebenen: Derjenige erhält eine Belohnung. der den Täter anzeigt der den Pfahl umgeworfen hat der an der Brücke steht die an dem Weg liegt der nach Jena führt Auf jeder Ebene, bis auf die unterste, wird der Textfluss unterbrochen und später fortgesetzt. Die Darstellung hat jedoch Grenzen, da auf den Ebenen vollkommen andere Texte stehen. 2.6 Zugang über Handlungsabläufe Mit dem folgenden Beispiel wird an die zweite Strukturierung des Schachtelsatzes aus Abschnitt 2.5 angeknüpft. Es klingelt. Ich lasse Anna herein und sage Anna guten Tag. Es klingelt. Ich lasse Bert herein und sage Bert guten Tag. Es klingelt. Ich lasse Clara herein und sage Clara guten Tag. Es klingelt. Ich lasse Dirk herein und sage Dirk guten Tag. Bevor ich Anna, Bert und Clara begrüßen kann, klingelt es wieder. Meine Tätigkeit wird von einer gleichartigen Tätigkeit unterbrochen. Ich begrüße erst Dirk, dann Clara, Bert und Anna (vgl. Thüringer Abiturprüfung Grundfach Informatik 2001, Aufgabe 1.1). Ein rekursiver Algorithmus soll alle Anordnungen (Permutationen) von gegebenen Elementen ermitteln. Der Algorithmus wird nachfolgend an den Elementen ▲,■, und ● erläutert. Mithilfe von Tauschoperationen werden die folgenden Viererfolgen erzeugt: ▲■ ● ▲■● ▲● ■ ●■ ▲ Jedes der vier Elemente steht einmal an der vierten Position. Nach dem Erzeugen einer jeden Viererfolge werden mithilfe von Tauschoperationen Dreierfolgen erzeugt. Das Element an der vierten Position bleibt dabei fest. Zum Beispiel werden aus der zweiten Viererfolge die folgenden Dreierfolgen erzeugt: ▲■● ▲●■ ●■▲ Jedes der drei Elemente steht einmal an der dritten Position. Nach dem Erzeugen einer jeden Dreierfolge werden mithilfe von Tauschoperationen Zweierfolgen erzeugt. Die Elemente an der dritten und vierten Position bleiben dabei fest. Zum Beispiel werden aus der dritten Dreierfolge die folgenden Zweierfolgen erzeugt: ●■▲ ■●▲ Jedes der beiden Elemente steht einmal an der zweiten Position. Das beschriebene Handlungsmuster ist unabhängig von der Anzahl an Elementen einer Folge. Mit dem rekursiven Vorgehen werden die 24 Permutationen für die gegebenen vier Elemente ermittelt. 2.7 Vergleichen von Rekursion und Iteration Mit den sechs Zugängen kann Rekursion im Informatikunterricht in unterschiedlicher Weise ohne Computereinsatz thematisiert werden. Der Autor hat im eigenen Unterricht die Erfahrung gemacht, dass das Behandeln mehrerer Zugänge eine gute Voraussetzung für das inhaltliche Verständnis von Rekursion ist. Rekursion und Iteration können auf hohem Abstraktionsniveau verglichen werden. Bei beiden handelt es sich um Formen der Wiederholung. Rekursion kann als Wiederholung strukturgleicher Blöcke durch Schachtelung, Iteration als Wiederholung strukturgleicher Blöcke durch Aneinanderreihung gekennzeichnet werden. Iteration: Rekursion: 3 Rekursive Problemlösungen auf dem Computer In diesem Abschnitt sind exemplarisch zehn Probleme aufbereitet, die unterschiedlichen Schwierigkeitsgrad besitzen und an denen Grundlagen zur Rekursion auf der Ebene der Realisierung vermittelt werden können. Rekursive Programme zur Berechnung von Gliedern der FIBONACCI-Zahlenfolge und anderer rekursiv definierter Zahlenfolgen sowie von Funktionswerten der Fakultätsfunktion fehlen nachfolgend, da diese Berechnungen aus Effizienzgründen iterativ oder mit einer Tabelle erfolgen sollten (vgl. WINKLER&NIEVERGELT). 3.1 Überführen von Dezimal- in Dualzahlen Die Schülerinnen und Schüler wissen, dass Computer intern im Dualsystem arbeiten. Eine Konsequenz davon ist, dass eine Dezimalzahl, die vom Computer eingelesen wird, vor der Verarbeitung in die gleichwertige Dualzahl zu überführen ist. Das folgende Python-Programm löst diese Aufgabe: def dual(zahl) : ganz = zahl / 2 rest = zahl % 2 if rest == 0 : zeichen = '0' else : zeichen = '1' if ganz == 0 : # Division ohne Rest # Rest der Division # Test auf Gleichheit return zeichen else : return dual(ganz) + zeichen n = input('ganze Zahl:') print dual(n) Im Unterricht kann an dem Beispiel erläutert werden, wie rekursive Programme vom Computer abgearbeitet werden. In der vorletzten Zeile wird der Wert der ganzzahligen Variablen n eingelesen (z. B. 113) und in der letzten Zeile wird mit dual(n) die Funktion dual das erste Mal aufgerufen. Der Wert 113 wird an den Wertparameter zahl der Funktion dual übergeben und es werden die Werte für die lokalen Variablen berechnet: ganz=56, rest=1 und zeichen='1'. Mit dual(56) ruft sich die Funktion dual rekursiv auf. Wir nennen dies den rekursiven Abstieg. Weitere Selbstaufrufe sind dual(28), dual(14), dual(7), dual(3) und dual(1). Bei der Abarbeitung von dual(1) werden die Werte ganz=0, rest=1 und zeichen='1' ermittelt. Mit ganz=0 ist der rekursive Abbruch erreicht und die Funktion dual liefert das Zeichen '1' als Funktionswert. An dieses Zeichen werden beim rekursiven Aufstieg nacheinander die Zeichen '1', '1', '0', '0', '0' und '1' angehangen. Als Ergebnis entsteht die Zeichenkette '1110001'. Jedes Mal, wenn die Funktion dual zur Abarbeitung gebracht wird, werden die lokalen Variablen ganz, rest und zeichen erzeugt. Rekursion wird bei dieser Problemlösung eingesetzt, um alle Divisionsreste zu erzeugen und diese in umgekehrter Reihenfolge auszugeben. An dem Programm wird deutlich, dass Rekursion in Programmen durch einen Selbstaufruf von Unterprogrammen gekennzeichnet ist. Ein anderes Einstiegsbeispiel wäre z. B. ein Programm, das eine Zeichenfolge auf rekursive Art umdreht (erstes Zeichen abspalten, Rest-Zeichenfolge umdrehen, abgespaltenes Zeichen an die umgedrehte Rest-Zeichenfolge anhängen). 3.2 Größter gemeinsamer Teiler Taschenrechner, die mit gemeinen Brüchen operieren, können Ergebnisse kürzen, indem sie ein Unterprogramm, das den Algorithmus nach EUKLID ausführt, zur Abarbeitung bringen. Die Berechnung des ggT der ganzen Zahlen x und y kann iterativ mit einer Schleife erfolgen (Python-Programm): def ggT1(x, y) : while y > 0 : rest = x % y x=y y = rest return x a = 12 b = 40 g = ggT1(a, b) print g Die ggT-Berechnung lässt sich auch rekursiv formulieren: def ggT2(x, y) : if y == 0 : return x else : return ggT2(y, x % y) An diesem Beispiel erkennen die Schülerinnen und Schüler, wie eine iterative in eine rekursive Problemlösung umgesetzt wird. Es entsteht Endrekursion, bei der beim rekursiven Aufstieg keine Operationen mehr auszuführen sind. 3.3 Permutationen Der Handlungsablauf von Abschnitt 2.6 kann z. B. in ein Oberon-Programm umgesetzt werden. Entscheidend ist die Prozedur Perm. Bei vier Elementen ist Perm(3) der erste Aufruf dieser Prozedur. Der rekursive Abbruch liegt vor, wenn eine Folge nur aus einem Element besteht. PROCEDURE Perm(n: INTEGER); VAR k: INTEGER; BEGIN IF n = 0 THEN LoesungAusgeben ELSE FOR k := n TO 0 BY -1 DO Tausch(a[k], a[n]); Perm(n - 1); (* rekursiver Aufruf *) Tausch(a[k], a[n]) END END END Perm; Das Programm kann im Informatikunterricht beim Lösen von verschiedenen Problemen genutzt werden. Ein Beispiel ist das Problem des Handlungsreisenden, bei dem eine kürzeste Rundreise durch n Städte gesucht wird. Die Permutation 1 4 3 2 beschreibt die folgende Rundreise: Beginnend in der Stadt 1 geht es nacheinander in die Städte 4, 3 und 2 und dann wieder zur Ausgangsstadt 1. Zur Lösung sind drei Teile zu erarbeiten: Ermitteln aller Permutationen, Ermitteln der Länge einer jeden Rundreise, Heraussuchen einer kürzesten Rundreise (vgl. Thüringer Abiturprüfung Leistungsfach Informatik 2001, Aufgabe 3.2). Diese Methode des systematischen Durchprobierens aller Varianten ist nur für wenige Städte anwendbar, da die benötigte Rechenzeit exponentiell mit der Problemgröße, der Anzahl an Städten, ansteigt. 3.4 Türme von Hanoi Bei dem bekannten Spiel „Türme von Hanoi“ sind Scheiben von einem Feld auf ein anderes in möglichst wenigen Schritten zu versetzen. Auf einem dritten Feld können Scheiben zwischengelagert werden. Beim Versetzen sind zwei Spielregeln zu beachten: Versetze immer nur eine Scheibe von einem Feld auf ein anderes und lege stets eine kleinere Scheibe auf eine größere (vgl. 43. Mathematik-Olympiade, 1. Stufe, Klasse 6, Aufgabe 430612). Bei der rekursiven Lösung wird der Begriff Turm eingeführt und verwendet. Das Versetzen eines Turmes, der aus k Scheiben besteht, wird auf das zweimalige Versetzen eines Turms, der aus k-1 Scheiben besteht, zurückgeführt. Der rekursive Abbruch liegt vor, wenn der zu versetzende Turm aus 0 Scheiben besteht. Nach dieser Vorschrift sind ganze Türme zu versetzen, obwohl nach den Spielregeln nur einzelne Scheiben bewegt werden dürfen. Die Schülerinnen und Schüler sollen erkennen, dass dieser Widerspruch durch wiederholtes Anwenden der Vorschrift aufgelöst wird. Die nachfolge Tabelle illustriert dies für einen Turm, der aus vier Scheiben besteht. Die rechte Spalte ist die Einzige, die ausschließlich direkt ausführbare Handlungen enthält. Turm(1, 1, 3) Turm(2, 1, 2) Scheibe(2, 1, 2) Turm(1, 3, 2) Turm(3, 1, 3) Scheibe(3, 1, 3) Scheibe(3, 1, 3) Turm(1, 2, 1) Turm(2, 2, 3) Scheibe(2, 2, 3) Turm(1, 1, 3) Turm(4, 1, 2) Scheibe(4, 1, 2) Scheibe(4, 1, 2) Scheibe(4, 1, 2) Turm(1, 3, 2) Turm(2, 3, 1) Scheibe(2, 3, 1) Turm(1, 2, 1) Turm(3, 3, 2) Scheibe(3, 3, 2) Scheibe(3, 3, 2) Turm(1, 1, 3) Turm(2, 1, 2) Scheibe(2, 1, 2) Turm(1, 3, 2) Turm(0, 1, 2) Scheibe(1, 1, 3) Turm(0, 2, 3) Scheibe(2, 1, 2) Turm(0, 3, 1) Scheibe(1, 3, 2) Turm(0, 1, 2) Scheibe(3, 1, 3) Turm(0, 2, 3) Scheibe(1, 2, 1) Turm(0, 3, 1) Scheibe(2, 2, 3) Turm(0, 1, 2) Scheibe(1, 1, 3) Turm(0, 2, 3) Scheibe(4, 1, 2) Turm(0, 3, 1) Scheibe(1, 3, 2) Turm(0, 1, 2) Scheibe(2, 3, 1) Turm(0, 2, 3) Scheibe(1, 2, 1) Turm(0, 3, 1) Scheibe(3, 3, 2) Turm(0, 1, 2) Scheibe(1, 1, 3) Turm(0, 2, 3) Scheibe(2, 1, 2) Turm(0, 3, 1) Scheibe(1, 3, 2) Turm(0, 1, 2) Scheibe(1, 1, 3) Scheibe(2, 1, 2) Scheibe(1, 3, 2) Scheibe(3, 1, 3) Scheibe(1, 2, 1) Scheibe(2, 2, 3) Scheibe(1, 1, 3) Scheibe(4, 1, 2) Scheibe(1, 3, 2) Scheibe(2, 3, 1) Scheibe(1, 2, 1) Scheibe(3, 3, 2) Scheibe(1, 1, 3) Scheibe(2, 1, 2) Scheibe(1, 3, 2) Die n Scheiben bekommen der Größe nach die Nummern von 1 bis n. Die kleinste Scheibe trägt die Nummer 1. Turm(k, a, b) bedeutet: Versetze den Turm, der aus k Scheiben besteht, von Feld a nach Feld b. Scheibe(k, a, b) bedeutet: Versetze Scheibe k von Feld a nach Feld b. Die rekursive Vorschrift ist Ausgangspunkt für die Programmentwicklung (vgl. z. B. FOTHE&KERNER (1988)). Aus der rekursiven Lösung lassen sich iterative herleiten. Eine Variante ist das wechselweise Anwenden der beiden folgenden Regeln: Lege die kleinste Scheibe eins weiter (entweder stets rechts herum oder stets links herum). Lege eine andere Scheibe. 3.5 Quicksort Der wichtige Sortieralgorithmus Quicksort besitzt eine rekursive Struktur. Beim Abarbeiten von Sort(L, R) werden die Elemente der Folge von aL bis aR in die richtige Reihenfolge gebracht. Die Prozedur Sort enthält zwei rekursive Aufrufe, und zwar für die linke Teilfolge der Elemente von aL bis aK und die rechte Teilfolge der Elemente von aI bis aR (Methode Teile und Herrsche). Der rekursive Abbruch liegt vor, wenn eine Teilfolge nur aus einem Element besteht. Das Zeit- und Speicherverhalten von Quicksort kann im Unterricht auf der Grundlage eines einfachen Modells thematisiert werden (vgl. FOTHE (2003)). Beim Speicherverhalten sind der Speicherplatz für die Elemente und die Einträge im Stack zu berücksichtigen. Im besten Fall liegen gleichzeitig bis zu ld n Einträge im Stack vor, im schlechtesten Fall sind es n-1. An dem Programm „Quicksort“ kann die interne Abarbeitung rekursiver Unterprogramme im Unterricht auf der Ebene einer Modellvorstellung thematisiert werden. Mit einem Stack (Stapel, Keller), der vom Laufzeitsystem der Programmiersprache automatisch verwaltet wird, kann ein rekursiv arbeitendes Programm auf einem Computer nach dem von-Neumann-Rechnermodell, der iterativ arbeitet, zur Abarbeitung gebracht werden. Bei jedem rekursiven Unterprogrammaufruf werden die Werte der Parameter und die der lokalen Variablen sowie die Rückkehradresse im Stack gespeichert und später wieder vom Stack geholt. 3.6 Suchbaum Auf rekursive Datenstrukturen kann auf rekursive Art zugegriffen werden. Ein Beispiel ist das Ausgeben eines binären Baumes mit der Methode Inorder, bei der zuerst der linke Teilbaum ausgegeben wird, dann die Daten der Wurzel und anschließend der rechte Teilbaum. Diese Vorschrift wird rekursiv auf jeden Teilbaum angewandt. Für den unter 2.4 angegebenen binären Baum ergibt sich die Zeichenfolge D, B, E, A, F, H, G, C. Bei einem speziellen binären Baum, dem Suchbaum, sind alle Daten im linken Teilbaum kleiner als die Daten der Wurzel und die Daten der Wurzel kleiner als alle Daten im rechten Teilbaum. Diese Regel wird rekursiv auf jeden Teilbaum angewandt. Aus den Definitionen von Inorder und Suchbaum folgt, dass die Methode Inorder bei einem Suchbaum die Daten der Knoten in der sortierten Reihenfolge liefert. 3.7 Speichern von Bildern 0 0 0 0 1 1 0 0 0 0 0 0 1 1 1 0 1 1 0 0 1 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 Das Bild wird in vier Quadranten aufgeteilt. Der erste Quadrant (rechts-oben) besteht ausschließlich aus Nullen. Daher wird für ihn eine 0 gespeichert. Der zweite Quadrant (links-oben) besteht aus Nullen und Einsen. Er wird wiederum in Quadranten zerlegt. Diese vier Quadranten bestehen einheitlich aus jeweils vier Nullen oder aus vier Einsen. Für den zweiten Quadranten wird (1,0,0,0) gespeichert. Der dritte Quadrant (links-unten) besteht aus Nullen und Einsen. Er wird weiter zerlegt und es zeigt sich, dass zwei dieser Quadranten nur aus Nullen bzw. nur aus Einsen bestehen und dass die beiden anderen Quadranten gemischt sind. Es ergibt sich ((0,1,1,0),1,(1,0,0,0),0). Der vierte Quadrant (rechts-unten) besteht einheitlich aus Einsen. Daher wird für ihn eine 1 gespeichert. Das ganze Bild kann mit (0,(1,0,0,0),((0,1,1,0),1,(1,0,0,0),0),1) gespeichert werden. Diese Zeichenfolge könnte in einen Viererbaum überführt werden und es könnten rekursive Unterprogramme zur Arbeit mit dem Baum angegeben werden. Ein Beispiel dafür ist das Drehen des Bildes um 90°, was durch Rotation der Knoten auf allen Ebenen des Baumes realisiert wird (vgl. DEWDNEY, S. 340-346). 3.8 Suchen in einem Labyrinth Die Labyrinthsuche ist ein Beispiel für das Problemlösungsverfahren Backtracking. Gesucht werden in einem rechteckigen Labyrinth alle Wege von einem Start- zu einem Zielfeld. Als Modell für das Labyrinth eignet sich ein zweidimensionales Array, dessen Elemente Zeichen sind. Nullen stellen die Wege, Einsen die Mauern oder Hecken dar. Zweien fassen das Labyrinth ein. Das Zeichen A symbolisiert das Startund das Zeichen B das Zielfeld. Die Prozedur Schritt führt einen zulässigen Schritt in dem Labyrinth aus und garantiert, dass im Suchprozess alle Varianten ausprobiert und dass Zyklen bei der Suche ausgeschlossen werden. Nach einem zulässigen Schritt erfolgt ein rekursiver Aufruf der Prozedur Schritt (vgl. FOTHE (2001)). In einer Projektarbeit können die Schülerinnen und Schüler ein vorgegebenes Programm für rechteckige Labyrinthe analysieren und es dann z. B. so modifizieren, dass es bei räumlichen Labyrinthen funktioniert. Bei einem räumlichen Labyrinth gibt es mehrere ebene Labyrinthe übereinander, die durch Leitern an einem oder an mehreren Feldern miteinander verbunden sind. 3.9 Hilbert-Kurven Das Problem kann in zwei Teilprobleme aufgeteilt werden. Das erste Teilproblem besteht darin, die Ordnung der Hilbert-Kurve einzulesen und eine Folge von Zeichenanweisungen zu erzeugen. Für die Hilbert-Kurve H2 (vgl. Abschnitt 2.2) ergibt sich die Folge SWNWWSESWSEENES. Das zweite Teilproblem besteht darin, diese Zeichenanweisungen einzulesen, zu interpretieren und eine Folge von gleich langen Strecken auf dem Bildschirm auszugeben. Das Programm zur Lösung des ersten Teilproblems enthält die vier rekursiv arbeitenden Prozeduren A, B, C und D. Nachfolgend ist exemplarisch der Quelltext der Prozedur A in Oberon angegeben (die anderen drei Prozeduren besitzen ähnlichen Aufbau). PROCEDURE A(i: INTEGER); BEGIN IF i > 0 THEN D(i - 1); Out.Char("W"); (* ein Schritt nach Westen *) A(i - 1); Out.Char("S"); (* ein Schritt nach Sueden *) A(i - 1); Out.Char("E"); (* ein Schritt nach Osten *) B(i - 1) END END A; Ein anderes Vorgehen beim Zeichnen NIEVERGELT&HINRICHS, S. 36 ff. von Hilbert-Kurven beschreiben 3.10 Syntaxanalyse Eine Möglichkeit für die Syntaxanalyse ist das Befolgen der Regel, dass sich die grammatikalische Struktur einer Sprache in der Struktur des Parsers widerspiegeln soll. Besitzt eine Sprachbeschreibung eine rekursive Struktur, so wird das entsprechende Programm zur Syntaxanalyse ebenfalls rekursiv aufgebaut sein (vgl. WIRTH (1986)). Das Erarbeiten eines einfachen Parsers eignet sich als Projektarbeit für besonders interessierte Schülerinnen und Schüler. 4 Resümee Das Thema Rekursion beinhaltet sowohl theoretische als auch praktische Aspekte. Theoretisches und Praktisches lässt sich bei der Behandlung im Unterricht gut miteinander verzahnen. Im Unterricht lassen sich Probleme mit Bezug zu Rekursion bearbeiten, die unterschiedlichen Komplexitäts- und Schwierigkeitsgrad besitzen. Bereits im Anfangsunterricht können einfache rekursive Problemlösungen erarbeitet werden. Die in der SI erworbenen Kenntnisse und Fähigkeiten lassen sich ohne Brüche schrittweise bis hin zum Bearbeiten von größeren Projekten in der SII ausbauen. Die in dieser Arbeit angegebenen Probleme stammen aus unterschiedlichen Gebieten und besitzen teilweise erhebliche Relevanz in Anwendungen. Das Thema „Rekursion und Iteration“ ist eines der Themen, die ich gemeinsam mit einigen Thüringer Gymnasien ab 2004 genauer untersuchen möchte. Jürgen F. H. Winkler danke ich für kritische Hinweise zu Entwürfen dieses Beitrags. 5 Literatur Barron, D. W.: Rekursive Techniken in der Programmierung. Teubner Leipzig 1971 Baumann, R.: Didaktik der Informatik. 2. Aufl. Klett Stuttgart, München, Düsseldorf, Leipzig 1996 Dewdney, A. K.: Der Turing Omnibus. Eine Reise durch die Informatik mit 66 Stationen. Springer Berlin, Heidelberg, New York 1995 Fothe, M.; Kerner, I. O.: Problem des Lucas. Wurzel, Jena 2/88, S. 18-23 Fothe, M.: Problemlösen mit OBERON. Konzeption und Einsatz eines elektronischen Lehrbuchs. LOG IN 21 (2001) Heft 2, S. 33-40 Fothe, M.: Problemlösen mit Python. Reihe „Materialien“, Heft 72 des ThILLM Bad Berka 2002 Fothe, M.: Zeitverhalten von Sortierverfahren – Beispiele für experimentelles Arbeiten im Informatikunterricht. In: Hubwieser, P. (Hrsg.): Informatische Fachkonzepte im Unterricht, INFOS 2003. Lecture Notes in Informatics (LNI). Bonn 2003, S. 111-120 Heyderhoff, P. (Hrsg.): Bundeswettbewerb Informatik. Aufgaben und Lösungen, Band 2. Klett Stuttgart 1990 Hubwieser, P.: Didaktik der Informatik. Grundlagen, Konzepte, Beispiele. Springer Berlin, Heidelberg, New York 2000 Nievergelt, J.; Hinrichs, K. H.: Algorithms and Data Structures. With Applications to Graphics and Geometry. Prentice Hall Englewood Cliffs 1993 Rechenberg, P.: Quo vadis Informatik? LOG IN 17 (1997) Heft 1, S. 25-32 Reiser, M.; Wirth, N.: Programming in Oberon. Steps beyond Pascal and Modula. ACM Press, New York; Addison-Wesley, Wokingham, Reading 1992 Schubert, S.; Schwill, A.: Didaktik der Informatik. Spektrum Akademischer Verlag Heidelberg, Berlin 2004 Wagenknecht, C.: Rekursion. Ein didaktischer Zugang mit Funktionen. Dümmler Bonn 1994 Winkler, J. F. H.; Nievergelt, J.: Wie soll die Fakultätsfunktion programmiert werden? InformatikSpektrum 12, 4 (1989) 220-221 Wirth, N.: Compilerbau. 4. Aufl. Teubner Stuttgart 1986 Autor: Prof. Dr. Michael Fothe Casio-Stiftungsprofessur Didaktik Informatik/Mathematik Friedrich-Schiller-Universität Jena Fakultät für Mathematik und Informatik 07740 Jena E-Mail [email protected]