1 4 Einführung in die Programmierung Chiang Mai Bertrand Meyer Letzte Aktualisierung: 15. Dezember 2003 Chair of Software Engineering Chair of Software Engineering Intro – Lecture 16 Intro – Lecture 16 2 5 Vorlesung 16: Einführung in die Rekursion Chair of Software Engineering Chair of Software Engineering Intro – Lecture 16 Intro – Lecture 16 3 Chair of Software Engineering Intro – Lecture 16 6 Chair of Software Engineering Intro – Lecture 16 1 7 Chair of Software Engineering Chair of Software Engineering Intro – Lecture 16 APSEC 2003 10 Intro – Lecture 16 8 11 Asia-Pacific Software Engineering Conference Chair of Software Engineering Chair of Software Engineering Intro – Lecture 16 Intro – Lecture 16 9 12 Vorlesung 16: Einführung in die Rekursion Chair of Software Engineering Intro – Lecture 16 Chair of Software Engineering Intro – Lecture 16 2 Die Geschichte des Universums* 13 *Gemäss Édouard Lucas, Récréations mathématiques, Paris, 1883 Dans le grand temple de Bénarès, sous le dôme qui marque le centre du monde, repose un socle de cuivre équipé de trois aiguilles verticales en diamant de 50 cm de haut. A la création, Dieu enfila 64 plateaux en or pur sur une des aiguilles, le plus grand en bas et les autres de plus en plus petits. C'est la tour de Brahmâ. Les moines doivent continûment déplacer les disques de manière que ceux-ci se retrouvent dans la même configuration sur une autre aiguille. La règle de Brahmâ est simple: un seul disque à la fois et jamais un grand plateau sur un plus petit. Daraus resultiert ein Algorithmus 16 move (n: INTEGER; source, target, other: CHARACTER) is -- Move n disks from needle source to target, -- using other as storage. do if n > 0 then move (n−1, source, other, target) transfer (source, target) move (n−1, other, target, source) end end Arrivé à ce résultat, le monde tombera en poussière et disparaîtra. Chair of Software Engineering Chair of Software Engineering Intro – Lecture 16 Die Geschichte des Universums* 14 Intro – Lecture 16 Der Begriff “Rekursion” 17 *Gemäss Édouard Lucas, Récréations mathématiques, Paris, 1883 In the great temple of Benares, under the dome that marks the center of the world, three diamond needles, a foot and a half high, stand on a copper base. God on creation strung 64 plates of pure gold on one of the needles, the largest plate at the bottom and the others ever smaller on top of each other. That is the tower of Brahmâ. The monks must continuously move the plates until they will be set in the same configuration on another needle. Eine Definition für ein Konzept ist rekursiv, wenn sie eine Instanz des Konzeptes selbst beinhaltet. Bemerkungen: The rule of Brahmâ is simple: only one plate at a time, and never a larger plate on a smaller one. • Die Definition kann mehr als eine “Instanz des Konzeptes selbst” benutzen. When they reach that goal, the world will crumble into dust and disappear. • Rekursion ist die Benutzung einer rekursiven Definition. Chair of Software Engineering Chair of Software Engineering Intro – Lecture 16 Wie viele Schritte? 15 Intro – Lecture 16 Beispiele 18 Beispiel: n Scheiben (n ≥ 0); drei Nadeln mit source, target und other bezeichnet. Rekursive Routinen Die grösste Scheibe kann nur dann von source nach target bewegt werden, wenn target leer ist; deshalb müssen alle anderen Scheiben auf other liegen. Rekursive Grammatiken Deshalb ist die minimale Anzahl der Bewegungen für jede Lösung: Move n−1 from source to other Move largest from source to target Hn = Hn−1 + 1 + Hn−1 = 2 * Hn−1 + 1 Chair of Software Engineering Move n−1 from other to target Rekursiv definierte Programm-Konzepte Rekursive Datenstrukturen Da Hn = 1, impliziert dies: Hn = 2n − 1 Intro – Lecture 16 Chair of Software Engineering Intro – Lecture 16 3 19 Rekursive Grammatik 22 Instruction = Assignment | Conditional | Compound | ... Conditional = Chair of Software Engineering Chair of Software Engineering Intro – Lecture 16 Rekursive Routine 20 Direkte Rekursion: Rumpf beinhaltet einen Aufruf der Routine selbst. Lexikographische Ordnung definieren 23 Konventionen: Ein Wort ist eine Sequenz von Null oder mehreren Buchstaben. Ein Buchstabe ist eines von: ABCDEFGHIJKLMNOPQRSTUVWXYZ Für beliebige zwei Buchstaben ist bekannt, welcher der beiden “kleiner” ist; die Ordnung ist die der vorherigen Liste. Chair of Software Engineering Intro – Lecture 16 Rekursion kann indirekt sein Intro – Lecture 16 Problem: Definiere, dass das Wort w1 “vor” dem Wort w2 ist, gemäss der lexikographischen Ordnung. Beispiel: Routine move der vorherigen Lösung des Problems “Türme von Hanoi”. Chair of Software Engineering if Expression then Instruction else Instruction end 21 Intro – Lecture 16 Beispiele Routine r beinhaltet einen Aufruf der Routine s ABC vor DEF s beinhaltet einen Aufruf von r AB vor DEF Allgemein: r1 ruft r2 ruft ... ruft rn ruft r1. Leeres Wort vor ABC 24 A vor AB A vor ABC Chair of Software Engineering Intro – Lecture 16 Chair of Software Engineering Intro – Lecture 16 4 Eine rekursive Definition Das Wort w1 ist nur dann “vor” dem Wort w2, wenn eine der folgenden Bedingungen zutrifft: Ein binärer Baum über einer sortierte Menge G ist ein binärer Suchbaum, wenn für jeder Knoten n gilt: Für jeden Knoten x des linken Teilbaums n, x.item ≤ n.item Weder w1 noch w2 sind leer, und der erste Buchstabe von w1 ist kleiner als der erste Buchstabe von w2 . Weder w1 noch w2 sind leer, die ersten Buchstaben sind die gleichen, und das Wort, das durch Entfernen des ersten Buchstabens von w1 entsteht, ist (rekursiv) vor dem Wort, das durch Entfernen des ersten Buchstabens von w2 entsteht. sort is do 11 51 left 29 -- Print element values in order if left /= Void then left.sort end if right /= Void then right.sort end end 59 end Chair of Software Engineering Intro – Lecture 16 class BINARY_TREE [G] feature item: G Intro – Lecture 16 Suchen in einem binären Suchbaum 27 30 class BINARY_SEARCH_TREE [G ...] feature item: G left, right: BINARY_SEARCH_TREE [G] right: BINARY_SEARCH_TREE [G] left: BINARY_TREE [G] right: BINARY_TREE [G] ... Insertion and deletion features ... end end Intro – Lecture 16 Intro – Lecture 16 print (item) Binärer Baum Klassen-Skelett Chair of Software Engineering 59 68 Right Chair of Software Engineering 51 class BINARY_SEARCH_TREE [G ...] feature item: G left, right: BINARY_SEARCH_TREE [G] right: BINARY_SEARCH_TREE [G] 72 20 11 Ausdrucken von Elementen in Reihenfolge 26 32 Ein binärer Baum über G ist entweder: Leer oder Ein Knoten, bestehend aus drei Elementen: Wert von Typ G Binärer Baum über G, genannt linkes Kind des Knotens Binärer Baum über G, genannt rechtes Kind des Knotens 72 20 68 Chair of Software Engineering G ist ein beliebiger Typ. 32 Für jeden Knoten x des rechten Teilbaums n, x.item ≥ n.item Intro – Lecture 16 Rekursive Datenstrukturen 28 Ein binärer Baum hat einen linken Teilbaum und einen rechten Teilbaum. w1 ist leer und w2 ist nicht leer. Chair of Software Engineering Binäre Suchbäume 25 has (x: G): BOOLEAN is -- Does a node in this subtree have value x? do if x < item then Result := ((left /= Void) and then left.has (x)) elseif x > item then Result := (right /= Void) and then right.has (x) else Result := True end end Chair of Software Engineering Intro – Lecture 16 5 Einfügen in einen binären Suchbaum Lösen sie dies als Übung! Chair of Software Engineering 34 move (n: INTEGER; source, target, other: CHARACTER) is -- Move n disks from needle source to target, -- using other as storage. do if n > 0 then move (n−1, source, other, target) transfer (source, target) move (n−1, other, target, source) end end Chair of Software Engineering Intro – Lecture 16 Warum binäre Suchbäume? Hanoi: Was ist die Variante? 31 Intro – Lecture 16 Ausdrucken: Was ist die Variante? 32 35 class BINARY_SEARCH_TREE [G ...] feature item: G left, right: BINARY_SEARCH_TREE [G] right: BINARY_SEARCH_TREE [G] Lineare Strukturen: Einfügen, Suchen und Löschen sind O (n). Binäre Suchbäume: Durchschnittliches Verhalten für Einfügen, Suchen und Löschen ist O (log (n)). sort is do Aber: Worst-time Verhalten ist O (n)! -- Print element values in order if left /= Void then left.sort end print (item) Beachte die Messung der Komplexität: best case, average, worst case. if right /= Void then right.sort end end end Chair of Software Engineering Chair of Software Engineering Intro – Lecture 16 Generelle Zuverlässigkeitseigenschaften Damit eine rekursive Definition Sinn macht: 33 Intro – Lecture 16 McCarthy’s 91 Funktion M (n) = Es muss einen nicht-rekursiven Zweig geben! n − 10 if n > 100 Eine nicht-negative Zahl — die Variante der Rekursion — muss bei jedem Aufruf niedriger werden. M (M (n + 11)) if n ≤ 100 Chair of Software Engineering Intro – Lecture 16 36 Chair of Software Engineering Intro – Lecture 16 6 Eine andere Funktion 37 bizarre (n) = 1 if n = 1 bizarre (n / 2) Unser Original-Beispiel für eine Schleife if n is even bizarre ((3 ∗ n + 1) / 2) if n > 1 and n is odd 1 count start Chair of Software Engineering Chair of Software Engineering Intro – Lecture 16 Fibonacci Zahlen 38 fib (1) = 0 fib (2) = 1 fib (n) = fib (n−2) + fib (n−1) Chair of Software Engineering n! = n * (n − 1)! for n > 0 Die Rekursive Definition ist nur für Demonstrationszwecke interessant; praktische Implementationen werden Schleifen (oder Tabellen) anwenden. Intro – Lecture 16 Ein rekursives Equivalent Chair of Software Engineering Intro – Lecture 16 0! = 1 forth 41 highest_name: STRING is -- Alphabetically greatest station name -- of line f require not f.is_empty do f.start Result := f.highest_from_cursor end for n > 2 Fakultätsfunktion 40 highest_name: STRING is -- Alphabetically greatest station name of line f do from f.start ; Result := "" until f.after loop Result := greater (Result, f.item.name) f.forth before after end item end 39 Intro – Lecture 16 Hilfsfunktion für Rekursion highest_from_cursor: STRING is -- Alphabetically greatest name of stations of -- line f starting at current cursor position require f /= Void; not f.off do Result := f.item.name f.forth if not f.after then Result := greater (Result, highest_from_cursor) end item end 1 42 after count forth Chair of Software Engineering Intro – Lecture 16 Chair of Software Engineering Intro – Lecture 16 7 Schleifen-Version mit Argumenten 43 maximum (a: ARRAY [STRING]): STRING is -- Alphabetically greatest item in a require a.count >= 1 local i: INTEGER do from i := a.lower + 1; Result := a.item (a.lower) invariant i > a.lower ; i <= a.upper + 1 -- Result is the maximum element of a [a.lower .. i−1] until i > a.upper loop if a.item (i) > Result then Result := a.item (i) end i := i + 1 end end Chair of Software Engineering x := x’ goto start_of_r ... Some instructions ... r (x’) ... More instructions ... Nach Aufruf Zurückgreifen auf vorherige Werte der Argumente und andere Kontextinformationen notwendig. Chair of Software Engineering 44 Intro – Lecture 16 Verwendung eines Stapels Abfragen: Ist der Stapel leer? is_empty Oberstes Element, wenn eines: item max_sub_array (a: ARRAY [STRING]; i: INTEGER): STRING is -- Alphabetically greatest item in a starting from index i require i >= a.lower ; i <= a.upper do Result := a.item (i) if i < a.upper then Result := greater (Result, max_sub_array (a, i + 1)) end end Kommandos: Lege ein Element an die Spitze: put Greife oberstes Element, wenn überhaupt eines: remove Chair of Software Engineering Intro – Lecture 16 Rekursions-Elimination Rekursive Aufrufe verursachen (in einer DefaultImplementation ohne Optimierung) eine LaufzeitEinbusse: Verwaltung eines Stapels für die aufbewahrten Werte notwendig. Verschiedene Optimierungen sind möglich. -- e.g. r (x–1) end maxrec (a: ARRAY [STRING]): STRING is -- Alphabetically greatest item in a require a.count >= 1 do Result := max_sub_array (a, a.lower) end Chair of Software Engineering 46 r (x) is do May need x! Intro – Lecture 16 Rekursive Version Rekursions-Elimination 45 47 “Top” position Intro – Lecture 16 Rekursion als eine Problem lösende Technik 48 Anwendbar — wenn man eine Möglichkeit hat, eine Lösung für ein Problem zu konstruieren — auf eine gewisse Inputmenge von Lösungen für eine oder mehrere kleinere Inputmengen. Manchmal kann eine Rekursion durch eine Schleife ersetzt werden; dies wird als Rekursions-Elimination bezeichnet. “Tail recursion” (letzte Anweisung einer Routine ist ein rekursiver Aufruf) kann gewöhnlich eliminiert werden. Chair of Software Engineering Intro – Lecture 16 Chair of Software Engineering Intro – Lecture 16 8 Dank an... 49 Fromageries Bel (La Vache qui rit) Yao Volksstamm Swiss Verschiedene andere Elefanten Thailändische Regierung Chair of Software Engineering Intro – Lecture 16 50 Ende Vorlesung 16 Chair of Software Engineering Intro – Lecture 16 9