Problemlösen mit Rekursion

Slides:



Advertisements
Ähnliche Präsentationen
Anzahl der ausgefüllten und eingesandten Fragebögen: 211
Advertisements

Vorlesung: 1 Betriebliche Informationssysteme 2003 Prof. Dr. G. Hellberg Studiengang Informatik FHDW Vorlesung: Betriebliche Informationssysteme Teil3.
Einführung in die Informatik: Programmierung und Software-Entwicklung
LS 2 / Informatik Datenstrukturen, Algorithmen und Programmierung 2 (DAP2)
Claudio Moraga; Gisbert Dittrich
LS 2 / Informatik Datenstrukturen, Algorithmen und Programmierung 2 (DAP2)
Telefonnummer.
Modelle und Methoden der Linearen und Nichtlinearen Optimierung (Ausgewählte Methoden und Fallstudien) U N I V E R S I T Ä T H A M B U R G November 2011.
Modelle und Methoden der Linearen und Nichtlinearen Optimierung (Ausgewählte Methoden und Fallstudien) U N I V E R S I T Ä T H A M B U R G November 2011.
1 JIM-Studie 2010 Jugend, Information, (Multi-)Media Landesanstalt für Kommunikation Baden-Württemberg (LFK) Landeszentrale für Medien und Kommunikation.
= = = = 47 = 47 = 48 = =
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (27 – Kürzeste Wege) Prof. Th. Ottmann.
Rechneraufbau & Rechnerstrukturen, Folie 2.1 © W. Oberschelp, G. Vossen W. Oberschelp G. Vossen Kapitel 2.
Internet facts 2008-II Graphiken zu dem Berichtsband AGOF e.V. September 2008.
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Vorlesung 2 SWS WS 99/00 Gisbert Dittrich FBI Unido
Vorlesung: 1 Betriebliche Informationssysteme 2003 Prof. Dr. G. Hellberg Studiengang Informatik FHDW Vorlesung: Betriebliche Informationssysteme Teil2.
Institut für Kartographie und Geoinformation Prof. Dr. Lutz Plümer Diskrete Mathematik I Vorlesung Listen-
Vererbung Spezialisierung von Klassen in JAVA möglich durch
PKJ 2005/1 Stefan Dissmann Rückblick auf 2005 Was zuletzt in 2005 vorgestellt wurde: Klassen mit Attributen, Methoden und Konstruktoren Referenzen auf.
PKJ 2005/1 Stefan Dissmann Zusammenfassung Bisher im Kurs erarbeitete Konzepte(1): Umgang mit einfachen Datentypen Umgang mit Feldern Umgang mit Referenzen.
Differentielles Paar UIN rds gm UIN
Prof. Dr. Bernhard Wasmayr
Studienverlauf im Ausländerstudium
Dieter Bergmann, Lichtenfels
LS 2 / Informatik Datenstrukturen, Algorithmen und Programmierung 2 (DAP2)
Datenstrukturen, Algorithmen und Programmierung 2 (DAP2)
Prof. Dr. Bernhard Wasmayr VWL 2. Semester
AWA 2007 Natur und Umwelt Natürlich Leben
Rechneraufbau & Rechnerstrukturen, Folie 12.1 © W. Oberschelp, G. Vossen W. Oberschelp G. Vossen Kapitel 12.
PRJ 2007/1 Stefan Dissmann Verkettete datenstruktur: Liste Problem: Liste, die eine beliebige Zahl von Elementen verwaltet Operationen: Erzeugen, Anfügen,
20:00.
Zusatzfolien zu B-Bäumen
Rekursion Klaus Becker (2002).
In der Schule.
Eine Einführung in die CD-ROM
Dokumentation der Umfrage
für Weihnachten oder als Tischdekoration für das ganze Jahr
Where Europe does business Lück, JDZB | Seite © GfW NRW 252 a.
Wir üben die Malsätzchen
Syntaxanalyse Bottom-Up und LR(0)
Einführung in die Programmierung
Institut für Wirtschaftsinformatik – Software Engineering, JKU Linz 1 Algorithmen und Datenstrukturen SS 2005 Mag.Th. Hilpold u. Dr. A.Stritzinger Institut.
2.4 Rekursion Klassifikation und Beispiele
PROCAM Score Alter (Jahre)
Ertragsteuern, 5. Auflage Christiana Djanani, Gernot Brähler, Christian Lösel, Andreas Krenzin © UVK Verlagsgesellschaft mbH, Konstanz und München 2012.
Geometrische Aufgaben
Kennst du dich aus mit Nadelbäumen?
Vorlesung Mai 2000 Konstruktion des Voronoi-Diagramms II
Symmetrische Blockchiffren DES – der Data Encryption Standard
Retuschen.ppt Die folgende Schau zeigt die Möglichkeiten, mit PhotoDraw Digitalbilder zu retuschieren. Vergleichen Sie jeweils zwei Bildpaare durch fleissiges.
1 (C)2006, Hermann Knoll, HTW Chur, FHO Quadratische Reste Definitionen: Quadratischer Rest Quadratwurzel Anwendungen.
Algorithmen und Datenstrukturen Übungsmodul 8
Zahlentheorie und Zahlenspiele Hartmut Menzer, Ingo Althöfer ISBN: © 2014 Oldenbourg Wissenschaftsverlag GmbH Abbildungsübersicht / List.
MINDREADER Ein magisch - interaktives Erlebnis mit ENZO PAOLO
1 (C)2006, Hermann Knoll, HTW Chur, FHO Quadratische Reste Definitionen: Quadratischer Rest Quadratwurzel Anwendungen.
Schutzvermerk nach DIN 34 beachten 20/05/14 Seite 1 Grundlagen XSoft Lösung :Logische Grundschaltung IEC-Grundlagen und logische Verknüpfungen.
Folie Beispiel für eine Einzelauswertung der Gemeindedaten (fiktive Daten)
Unternehmensbewertung Thomas Hering ISBN: © 2014 Oldenbourg Wissenschaftsverlag GmbH Abbildungsübersicht / List of Figures Tabellenübersicht.
SFZ FN Sj. 13/14 Python 3 Rekursion Inf K1/2 Sj 13/14
Es war einmal ein Haus
Folie Einzelauswertung der Gemeindedaten
1.6.3 Test auf Verlustfreiheit (Verbundtreue) (4|10)
J-Team: Gymnasium Ulricianum Aurich und MTV Aurich Ein Projekt im Rahmen von UlricianumBewegt.de Euro haben wir schon…  8000 mal habt ihr bereits.
Berechenbarkeit Klaus Becker Berechenbarkeit.
Datum:17. Dezember 2014 Thema:IFRS Update zum Jahresende – die Neuerungen im Überblick Referent:Eberhard Grötzner, EMA ® Anlass:12. Arbeitskreis Internationale.
Technische Kommunikation
Einführung in die Volkswirtschaftslehre, Mikroökonomie und Wettbewerbspolitik Lothar Wildmann ISBN: © 2014 Oldenbourg Wissenschaftsverlag.
Sehen, Hören, Schmecken: wenn uns unsere Sinne täuschen
1 Medienpädagogischer Forschungsverbund Südwest KIM-Studie 2014 Landesanstalt für Kommunikation Baden-Württemberg (LFK) Landeszentrale für Medien und Kommunikation.
Algorithmen und Datenstrukturen 1 SS 2002
 Präsentation transkript:

Problemlösen mit Rekursion Klaus Becker 2009

Problemlösen mit Rekursion Inhalte: Problemlösen durch Problemreduktion Selbstähnliche Figuren Rekursive Verarbeitung von Listen Rekursive Verarbeitung natürlicher Zahlen Rekursion und Berechnungsaufwand Rekursion und Iteration

Problemlösen durch Problemreduktion Teil 1 Problemlösen durch Problemreduktion

Einstieg - Türme von Hanoi Einer Geschichte zufolge soll im Tempel zu Benares - das ist eine "heilige Stadt" in Indien - ein Turm aus 64 goldenen, der Größe nach geordneten Scheiben stehen. Die Mönche des Tempels erhalten die Aufgabe, die Scheiben an einen anderen Ort zu bringen. Dabei müssen sie einige Regeln beachten: Es darf immer nur eine Scheibe transportiert werden. Scheiben können auf einem (einzigen) Hilfsstapel zwischenzeitlich abgelegt werden. Auch auf dem (teilweise abgebauten) Ausgangsturm können Scheiben zwischenzeitlich abgelegt werden. Es darf aber nie eine größere Scheibe auf eine kleinere gelegt werden. Wenn der neue Turm fertig ist, dann ist das Ende der Zeit erreicht.

Einstieg - Aufgabe (siehe 9.1.1) Versuchen Sie, einen Turm mit 5 Scheiben nach den vorgegebenen Regeln umzustapeln. Wenn das nicht klappt, dann versuchen Sie erst einmal, Türme mit 3 bzw. 4 Scheiben umzustapeln. Ausgangszustand Zielzustand Benutzen Sie Münzen unterschiedlicher Größe oder ein Simulationsprogramm. z. B.: http://www.mpg-trier.de/d7/prog/hanoi/hanoi.htm

Einstieg - Aufgabe (siehe 9.1.1) Überlegen Sie sich auch eine Strategie, mit der man Türme mit 6, 7, ... Scheiben umstapeln kann. Ausgangszustand Zielzustand

Lösungsidee transportiere einen 5-Scheiben-Turm von A über B nach C Ausgangszustand transportiere einen 4-Scheiben-Turm von A über C nach B Zwischenzustand transportiere eine Scheibe von A nach C Zwischenzustand transportiere einen 4-Scheiben-Turm von B über A nach C Zielzustand

Verallgemeinerung transportiere einen n-Scheiben-Turm von X über Y nach Z Ausgangszustand transportiere einen (n-1)-Scheiben-Turm von X über Z nach Y Zwischenzustand transportiere eine Scheibe von X nach Z Zwischenzustand transportiere einen (n-1)-Scheiben-Turm von Y über X nach Z Zielzustand

Algorithmus Algorithmus: transportiere einen n-Scheiben-Turm von X über Y nach Z wenn n > 1: transportiere einen (n-1)-Scheiben-Turm von X über Z nach Y transportiere eine Scheibe von X nach Z transportiere einen (n-1)-Scheiben-Turm von Y über X nach Z sonst:

Rekursive Problemreduktion Rekursive Problemreduktion ist eine Problemlösestrategie, bei der ein Problem auf ein strukturgleiches Problem (in verkleinerter Form) zurückgeführt wird. Algorithmus: transportiere einen n-Scheiben-Turm von X über Y nach Z wenn n > 1: transportiere einen (n-1)-Scheiben-Turm von X über Z nach Y transportiere eine Scheibe von X nach Z transportiere einen (n-1)-Scheiben-Turm von Y über X nach Z sonst: Ein rekursiver Algorithmus ruft sich (eventuell über Umwege) selbst auf und nutzt sich so selbst zur Beschreibung der Lösung des gegebenen Problems. Um Rekursion als Problemlösestrategie nutzen zu können, benötigt man ein Ausführsystem, das in der Lage ist, rekursive Algorithmen wiederholt aufzurufen und auf diese Weise die eigentliche Lösung zu generieren.

Ausführung des Algorithmus Algorithmus: transportiere einen n-Scheiben-Turm von X über Y nach Z wenn n > 1: transportiere einen (n-1)-Scheiben-Turm von X über Z nach Y transportiere eine Scheibe von X nach Z transportiere einen (n-1)-Scheiben-Turm von Y über X nach Z sonst: Ausführungstiefe: 1 transportiere einen 3-Scheiben-Turm von A über B nach C: transportiere einen 2-Scheiben-Turm von A über C nach B transportiere eine Scheibe von A nach C transportiere einen 2-Scheiben-Turm von B über A nach C

Ausführung des Algorithmus Algorithmus: transportiere einen n-Scheiben-Turm von X über Y nach Z wenn n > 1: transportiere einen (n-1)-Scheiben-Turm von X über Z nach Y transportiere eine Scheibe von X nach Z transportiere einen (n-1)-Scheiben-Turm von Y über X nach Z sonst: Ausführungstiefe: 2 transportiere einen 3-Scheiben-Turm von A über B nach C: transportiere einen 2-Scheiben-Turm von A über C nach B: transportiere einen 1-Scheiben-Turm von A über B nach C transportiere eine Scheibe von A nach B transportiere einen 1-Scheiben-Turm von C über A nach B transportiere eine Scheibe von A nach C transportiere einen 2-Scheiben-Turm von B über A nach C: transportiere einen 1-Scheiben-Turm von B über C nach A transportiere eine Scheibe von B nach C

Ausführung des Algorithmus Algorithmus: transportiere einen n-Scheiben-Turm von X über Y nach Z wenn n > 1: transportiere einen (n-1)-Scheiben-Turm von X über Z nach Y transportiere eine Scheibe von X nach Z transportiere einen (n-1)-Scheiben-Turm von Y über X nach Z sonst: Ausführungstiefe: 3 transportiere einen 3-Scheiben-Turm von A über B nach C: transportiere einen 2-Scheiben-Turm von A über C nach B: transportiere einen 1-Scheiben-Turm von A über B nach C: transportiere eine Scheibe von A nach C transportiere eine Scheibe von A nach B transportiere einen 1-Scheiben-Turm von C über A nach B: transportiere eine Scheibe von C nach B transportiere einen 2-Scheiben-Turm von B über A nach C: transportiere einen 1-Scheiben-Turm von B über C nach A: transportiere eine Scheibe von B nach A transportiere eine Scheibe von B nach C

Ausführung des Algorithmus transportiere einen 3-Scheiben-Turm von A über B nach C: transportiere einen 2-Scheiben-Turm von A über C nach B: transportiere einen 1-Scheiben-Turm von A über B nach C: transportiere eine Scheibe von A nach C transportiere eine Scheibe von A nach B transportiere einen 1-Scheiben-Turm von C über A nach B: transportiere eine Scheibe von C nach B transportiere einen 2-Scheiben-Turm von B über A nach C: transportiere einen 1-Scheiben-Turm von B über C nach A: transportiere eine Scheibe von B nach A transportiere eine Scheibe von B nach C Basisaktionen

Implementierung in Python Algorithmus: transportiere einen n-Scheiben-Turm von X über Y nach Z wenn n > 1: transportiere einen (n-1)-Scheiben-Turm von X über Z nach Y transportiere eine Scheibe von X nach Z transportiere einen (n-1)-Scheiben-Turm von Y über X nach Z sonst: Algorithmus def transportiereTurm(n, x, y, z): if n > 1: transportiereTurm(n-1, x, z, y) print "transportiere eine Scheibe von ", x, " nach ", z transportiereTurm(n-1, y, x, z) else: Python-Programm

Übungen (siehe 9.1.4) Bearbeiten Sie die Aufgaben 1, 2.

Selbstähnliche Figuren Teil 2 Selbstähnliche Figuren

Einstieg - Selbstähnliche Figur Eine Figur ist selbstähnlich, wenn sie sich in Teile zerlegen lässt, die zur ihr ähnlich sind.

Einstieg - Selbstähnliche Figur Eine Figur ist selbstähnlich, wenn sie sich in Teile zerlegen lässt, die zur ihr ähnlich sind. zeichne_Baum(200): gehe_vorwaerts(200) drehe_dich_nach_rechts(45) zeichne_Baum(100) drehe_dich_nach_links(90) gehe_rueckwaerts(200) ALG zeichne_Baum(x): wenn x >-> 2: gehe_vorwaerts(x) drehe_dich_nach_rechts(45) zeichne_Baum(x/2) drehe_dich_nach_links(90) gehe_rueckwaerts(x) rekursive Problemreduktion rekursiver Algorithmus

Exkurs - Turtle-Grafik Turtle-Grafik basiert auf der Vorstellung, dass eine Schildkröte mit bestimmten Anweisungen auf einer Zeichenfläche bewegt wird und dass die Schildkröte dabei eine Spur hinterlässt. vorwaerts(100) Turtle-Befehle zeichne_Quadrat(laenge): wiederhole 4 mal: gehe_vorwaerts(laenge) drehe_dich_nach_links(90) stift_hoch stift_runter gehe_vorwaerts(betrag) gehe_rueckwaerts(betrag) drehe_dich_nach_links(winkel) drehe_dich_nach_rechts(winkel) gehe_zu_punkt(punkt) ... Turtle-Algorithmus

Exkurs - Turtle-Grafik in Python Turtle-Grafik basiert auf der Vorstellung, dass eine Schildkröte mit bestimmten Anweisungen auf einer Zeichenfläche bewegt wird und dass die Schildkröte dabei eine Spur hinterlässt. zeichne_Quadrat(laenge): wiederhole 4 mal: gehe_vorwaerts(laenge) drehe_dich_nach_links(90) stift_hoch stift_runter gehe_vorwaerts(betrag) gehe_rueckwaerts(betrag) drehe_dich_nach_links(winkel) drehe_dich_nach_rechts(winkel) gehe_zu_punkt(punkt) ... Turtle-Programm # -*- coding: iso-8859-1 -*- from turtle import * # Deklaration einer Zeichenprozedur def quadrat(laenge): for i in range(4): t.forward(laenge) t.left(90) # Erzeugung eines Turtle-Objekts t = Turtle() # Test der Zeichenprozedur quadrat(100) Turtle-Klasse t.forward(100)

Exkurs - Turtle-Grafik in Python # -*- coding: iso-8859-1 -*- from turtle import * # Deklaration einer Zeichenprozedur def baum(stamm): if stamm >= 2: t.forward(stamm) t.right(45) baum(stamm/2) t.left(90) t.backward(stamm) # Erzeugung eines Turtle-Objekts t = Turtle() # Test der Zeichenprozedur baum(200) ALG zeichne_Baum(x): wenn x >= 2: gehe_vorwaerts(x) drehe_dich_nach_rechts(45) zeichne_Baum(x/2) drehe_dich_nach_links(90) gehe_rueckwaerts(x)

Übungen (siehe 9.2.3) Wählen Sie eine der folgenden selbstähnlichen Figuren aus. Entwickeln Sie mit Hilfe einer rekursive Problemreduktion einen rekursiven Algorithmus zum Zeichnen der Figur. Testen Sie den Algorithmus mit einer Python-Implementierung.

Übungen (siehe 9.2.3) Wählen Sie eine der folgenden selbstähnlichen Figuren aus. Entwickeln Sie mit Hilfe einer rekursive Problemreduktion einen rekursiven Algorithmus zum Zeichnen der Figur. Testen Sie den Algorithmus mit einer Python-Implementierung.

Übungen (siehe 9.2.3) Wählen Sie eine der folgenden selbstähnlichen Figuren aus. Entwickeln Sie mit Hilfe einer rekursive Problemreduktion einen rekursiven Algorithmus zum Zeichnen der Figur. Testen Sie den Algorithmus mit einer Python-Implementierung.

Übungen (siehe 9.2.3) Wählen Sie eine der folgenden selbstähnlichen Figuren aus. Entwickeln Sie mit Hilfe einer rekursive Problemreduktion einen rekursiven Algorithmus zum Zeichnen der Figur. Testen Sie den Algorithmus mit einer Python-Implementierung.

Übungen (siehe 9.2.3) Wählen Sie eine der folgenden selbstähnlichen Figuren aus. Entwickeln Sie mit Hilfe einer rekursive Problemreduktion einen rekursiven Algorithmus zum Zeichnen der Figur. Testen Sie den Algorithmus mit einer Python-Implementierung.

Übungen (siehe 9.2.3) Wählen Sie eine der folgenden selbstähnlichen Figuren aus. Entwickeln Sie mit Hilfe einer rekursive Problemreduktion einen rekursiven Algorithmus zum Zeichnen der Figur. Testen Sie den Algorithmus mit einer Python-Implementierung.

Rekursive Verarbeitung von Listen Teil 3 Rekursive Verarbeitung von Listen

Einstieg - Geschachtelte Listen Eine Gästeliste soll mit einem Programm verwaltet und verarbeitet werden. gaeste = ["Ursula", "Winfried", "Ulrike", "Klaus", ...] def ausgabe(liste): i = 0 while i < len(liste): element = liste[i] print element i = i + 1 def ausgabe(liste): if len(liste) == 0: pass else: erstesElement = liste[0] restListe = liste[1:] print erstesElement ausgabe(restListe) iterativ # Test ausgabe(gaeste) rekursiv

Einstieg - Geschachtelte Listen Eine Gästeliste soll mit einem Programm verwaltet und verarbeitet werden. gaeste = \ [ \ ["Ursula", "Winfried"], \ ["Ulrike", "Klaus"], \ ["Christiane", "Tim"], \ ["Andreas"], \ ["Ulrike", "Peter", ["Kea", "Lena", "Paula"]], \ ... ] def ausgabe(liste): if len(liste) == 0: pass else: erstesElement = liste[0] restListe = liste[1:] if type(erstesElement) == list: ausgabe(erstesElement) print erstesElement ausgabe(restListe) ? iterativ rekursiv # Test ausgabe(gaeste)

Einstieg - Geschachtelte Listen ausgabe([["Ursula", "Winfried"], ["Ulrike", "Klaus"], ["Christiane", "Tim"], ...]) ausgabe(["Ursula", "Winfried"]) print "Ursula" ausgabe(["Winfried"]) print "Winfried" ausgabe([]) pass ausgabe([["Ulrike", "Klaus"], ["Christiane", "Tim"], ...] ausgabe(["Ulrike", "Klaus"]) print "Ulrike" ausgabe(["Klaus"]) print "Klaus" ausgabe([]) ausgabe([["Christiane", "Tim"], ...]) ... def ausgabe(liste): if len(liste) == 0: pass else: erstesElement = liste[0] restListe = liste[1:] if type(erstesElement) == list: ausgabe(erstesElement) print erstesElement ausgabe(restListe) Ausführung rekursiver Algorithmus

Liste als rekursive Datenstruktur Eine Liste ist entweder eine leere Liste, oder besteht aus einem ersten Element und einer (Rest-)Liste. def ausgabe(liste): if len(liste) == 0: # liste == [] pass else: # liste == [erstesElement] + restListe erstesElement = liste[0] restListe = liste[1:] print erstesElement ausgabe(restListe) def ausgabe(liste): if len(liste) == 0: # liste == [] pass else: # liste == [erstesElement] + restListe erstesElement = liste[0] restListe = liste[1:] if type(erstesElement) == list: ausgabe(erstesElement) else: print erstesElement ausgabe(restListe)

Entwicklung rekursiver Algorithmen Problem: Es soll gezählt werden, wie oft ein Element in einer Liste vorkommt. Fall 1: Bearbeite eine leere Liste anzahl('b', []) -> Reduktionsanfang: Löse das Problem direkt Fall 2: Bearbeite eine nicht-leere Liste anzahl('b', ['b', 'b', 'd', 'a', 'c', 'b']) -> 1 + anzahl('b', ['b', 'd', 'a', 'c', 'b']) anzahl('b', ['a', 'b', 'b', 'd', 'a', 'c', 'b']) -> anzahl('b', ['b', 'b', 'd', 'a', 'c', 'b']) Rekursionsschritt: Löse ein entsprechendes Problem Rekursive Problemreduktion: Reduziere des Problems auf ein entsprechendes, aber „verkleinertes“ Problem.

Entwicklung rekursiver Algorithmen Problem: Es soll gezählt werden, wie oft ein Element in einer Liste vorkommt. anzahl('b', []) -> anzahl('b', ['b', 'b', 'd', 'a', 'c', 'b']) -> 1 + anzahl('b', ['b', 'd', 'a', 'c', 'b']) anzahl('b', ['a', 'b', 'b', 'd', 'a', 'c', 'b']) -> anzahl('b', ['b', 'b', 'd', 'a', 'c', 'b']) def anzahl(element, liste): if len(liste) == 0: return 0 else: if liste[0] == element: return (1 + anzahl(element, liste[1:])) return anzahl(element, liste[1:]) (rekursive) Reduktionsschritte (rekursive) Reduktionsregeln Rekursive Problemreduktion: Reduziere des Problems auf ein entsprechendes, aber „verkleinertes“ Problem.

Entwicklung rekursiver Algorithmen Problem: Es soll gezählt werden, wie oft ein Element in einer Liste vorkommt. anzahl('b', ['a', 'b', 'd', 'a', 'b']) -> anzahl('b', ['b', 'd', 'a', 'b']) -> 1 + anzahl('b', ['d', 'a', 'b']) -> 1 + anzahl('b', ['a', 'b']) -> 1 + anzahl('b', ['b']) -> 1 + (1 + anzahl('b', [])) -> 1 + (1 + 0) -> 2 def anzahl(element, liste): if len(liste) == 0: return 0 else: if liste[0] == element: return (1 + anzahl(element, liste[1:])) return anzahl(element, liste[1:]) Reduktionskette (rekursive) Reduktionsregeln >>> anzahl('b', ['a', 'b', 'd', 'a', 'b']) 2

Übungen (siehe 9.2.3) Rekursionsgymnastik: Bearbeiten Sie die Aufgaben des Abschnitts 9.2.3.

Fallstudie - geometrische Objekte In den folgenden Aufgaben (siehe 9.3.4) geht es um die Verwaltung und Verarbeitung geometrischer Objekte. Wir betrachten vereinfachend nur geometrische Objekte, die aus Streckenzügen mit Punkten mit ganzzahligen Koordinaten bestehen. Die folgende Abbildung (Logo des Fachbereichs Informatik der TU Kaiserslautern) ist aus solchen geometrischen Objekte aufgebaut. stuetzelinks = [[0, 0],[20, 0],[50, 100],[30, 100],[0, 0]] blockunten = [[90, 10],[110, 10],[110, 30],[90, 30],[90, 10]] blockoben = [[90, 70],[110, 70],[110, 90],[90, 90],[90, 70]] raute = [[80, 50],[100, 40],[120, 50],[100, 60],[80, 50]] verbindung1 = [[100, 110], [100, 90]] verbindung2 = [[100, 70], [100, 60]] verbindung3 = [[100, 40], [100, 30]] verbindung4 = [[100, 10], [100, 0]] verbindung5 = [[80, 50], [70, 50], [70, 100], [100, 100]] stuetzerechts = [verbindung1, blockoben, verbindung2, raute, \ verbindung5, verbindung3, blockunten, verbindung4] dach = [[10, 110],[130, 110],[130, 125],[70, 140],[10, 125],[10, 110]] tor = [stuetzelinks, stuetzerechts, dach] rahmen = [[0, 0],[140, 0],[140, 140],[0, 140],[0, 0]] logo = [tor, rahmen] Bearbeiten Sie die Aufgaben aus Abschnitt 9.3.4.

Rekursive Verarbeitung natürlicher Zahlen Teil 4 Rekursive Verarbeitung natürlicher Zahlen

Einstieg - Wege im Galton-Brett Ein Galton-Brett besteht aus Stäben, die in Reihen untereinander versetzt angeordnet sind. Wenn man eine Kugel ein solches Galton-Brett herunterrollen lässt, dann trifft es auf jeweils auf einen Stab und rollt dann entweder links oder rechts davon weiter herunter.

Einstieg - Aufgabe (siehe 9.4.1) Die Stäbe in der Abbildung oben sind bereits mit Stab-Koordinaten versehen. Mit diesen Koordinaten könnte man einen möglichen Kugelweg so beschreiben: (0,0), (1, 0), (2, 1), (3, 2), (4, 3), (5, 3). Wie viele Wege gibt es im Galton-Brett bis zum Stab (m, n)? Bestimmen Sie für alle Stäbe erst einmal die jeweilige Anzahl. Zur Kontrolle: Bis zum Stab (5, 3) gibt es 10 Wege.

Einstieg - Aufgabe (siehe 9.4.1) Die Funktion galton(m, n) beschreibe die Anzahl der Wege im Galton-Brett bis zum Stab (m, n). Begründen Sie die unten formulierten Eigenschaften der Funktion galton. galton(2, 0) galton(n, 0) -> 1 galton(n, n) -> 1 galton(m, n) -> galton(m-1, n-1) + galton(m-1, n), falls m > 0 und 0 < n < m gilt.

Einstieg - Aufgabe (siehe 9.4.1) Testen Sie die folgenden Funktionsdefinitionen. Worin unterscheiden sie sich? Welche ist korrekt? def galton(m, n): if m < n: return None else: if (n == 0) or (m == n): return 1 return (galton(m-1, n-1) + galton(m-1, n)) def galton(m, n): if m < n: return 0 else: if n == 0: return 1 return (galton(m-1, n-1) + galton(m-1, n)) def galton(m, n): if m == 0: if n == 0: return 1 else: return 0 return (galton(m-1, n-1) + galton(m-1, n))

Rekursive Struktur natürlicher Zahlen Eine natürliche Zahl ist entweder eine Null oder Nachfolger einer natürlichen Zahl. Problem: Die Summe der ersten n natürlichen Zahlen soll berechnet werden. Fall 1: Bearbeite die Zahl 0. summe(0) -> Reduktionsanfang: Löse das Problem direkt Fall 2: Bearbeite den Nachfolger einer natürlichen Zahl summe(5) -> 5 + summe(4) Rekursionsschritt: Löse ein entsprechendes Problem Rekursive Problemreduktion: Reduziere des Problems auf ein entsprechendes, aber „verkleinertes“ Problem.

Entwicklung rekursiver Algorithmen Problem: Die Summe der ersten n natürlichen Zahlen soll berechnet werden. summe(0) -> summe(5) -> 5 + summe(4) def summe(zahl): if zahl == 0: return 0 else: return zahl + summe(zahl-1) (rekursive) Reduktionsschritte (rekursive) Reduktionsregeln Rekursive Problemreduktion: Reduziere des Problems auf ein entsprechendes, aber „verkleinertes“ Problem.

Entwicklung rekursiver Algorithmen Problem: Die Summe der ersten n natürlichen Zahlen soll berechnet werden. summe(5) -> 5 + summe(4) -> 5 + (4 + summe(3)) -> 5 + (4 + (3 + summe(2))) -> 5 + (4 + (3 + (2 + summe(1)))) -> 5 + (4 + (3 + (2 + (1 + summe(0))))) -> 5 + (4 + (3 + (2 + (1 + 0)))) -> 5 + (4 + (3 + (2 + 1))) -> 5 + (4 + (3 + 3)) -> 5 + (4 + 6) -> 5 + 10 -> 15 def summe(zahl): if zahl == 0: return 0 else: return zahl + summe(zahl-1) (rekursive) Reduktionsregeln >>> summe(5) 15 Reduktionskette

Übungen (siehe 9.4.3) Rekursionsgymnastik: Bearbeiten Sie die Aufgaben des Abschnitts 9.4.3.

Fallstudie - natürliche Zahlen Operationen auf natürlichen Zahlen lassen sich alle aus einer einzigen Grundoperationen entwickeln. Man benötigt hierzu nur die Nachfolger-Operation s: N -> N, die jeder natürlichen Zahl n ihren Nachfolger s(n) zuordnet. add(x,0) -> x add(x,s(y)) -> s(add(x,y)) def s(x): return x+1 def p(x): return x-1 def add(x, y): if y == 0: return x else: return s(add(x, p(y))) (rekursive) Reduktionsregeln Implementierung in Python Bearbeiten Sie die Aufgaben aus Abschnitt 9.4.4.

Rekursion und Berechnungsaufwand Teil 5 Rekursion und Berechnungsaufwand

Einstieg - Wege im Galton-Brett Warum handelt es sich hier um ein ineffizientes Berechnungsverfahren? >>> galton(5, 3) galton( 5 , 3 ) galton( 4 , 2 ) galton( 3 , 1 ) galton( 2 , 0 ) galton( 2 , 1 ) galton( 1 , 0 ) galton( 1 , 1 ) galton( 3 , 2 ) galton( 2 , 2 ) galton( 4 , 3 ) galton( 3 , 3 ) 10 def galton(m, n): print "galton(", m, ",", n, ")" if m < n: return None else: if (n == 0) or (m == n): return 1 return (galton(m-1, n-1) + galton(m-1, n))

Ackermann-Funktion "Die Ackermannfunktion ist eine 1926 von Wilhelm Ackermann gefundene, extrem schnell wachsende mathematische Funktion, mit deren Hilfe in der theoretischen Informatik Grenzen von Computer- und Berechnungsmodellen aufgezeigt werden können. Heute gibt es eine ganze Reihe von Funktionen, die als Ackermannfunktion bezeichnet werden. Diese weisen alle ein ähnliches Bildungsgesetz wie die ursprüngliche Ackermannfunktion auf und haben auch ein ähnliches Wachstumsverhalten." (wikipedia) ack(0, y) -> y+1 ack(x, 0) -> ack(x-1, 1), falls x > 0 ack(x, y) -> ack(x-1, ack(x, y-1)), falls y > 0

Auswertung der Ackermann-Funktion Setzen Sie die Reduktionskette einige Schritte weiter fort. Wollen Sie es zu Ende rechnen? ack(0, y) -> y+1 ack(x, 0) -> ack(x-1, 1), falls x > 0 ack(x, y) -> ack(x-1, ack(x, y-1)), falls y > 0 ack(3, 2) -> ack(2, ack(3, 1)) -> ack(2, ack(2, ack(3, 0))) -> ack(2, ack(2, ack(2, 1))) ->

Implementierung d. Ackermann-Funkt. Implementieren Sie die Ackermann-Funktion in Python so, dass jeder Funktionsaufruf mit den aktuellen Parameterwerten auf dem Bildschirm ausgegeben wird (vgl. galton). Testen Sie verschiedene Funktionsaufrufe wie z. B. ack(2, 3) und ack(3, 2). Was fällt auf? ack(0, y) -> y+1 ack(x, 0) -> ack(x-1, 1), falls x > 0 ack(x, y) -> ack(x-1, ack(x, y-1)), falls y > 0

Eigenschaften der Ackermann-Funktion Informieren Sie sich (z. B. bei Wikipedia) über das Wachstumsverhalten der Ackermann-Funktion. Quelle: http://de.wikipedia.org/wiki/Ackermannfunktion

Berechnungsaufwand Warum stößt man bei der Berechnung der Ackermann-Funktion sehr schnell auf Grenzen - sowohl hinsichtlich der Rechenzeit als auch hinsichtlich des Speicherbedarfs? ack(4, 3) -> ack(3, ack(4, 2)) -> ack(3, ack(3, ack(4, 1))) -> ack(3, ack(3, ack(3, ack(4, 0)))) -> ack(3, ack(3, ack(3, ack(3, 1)))) -> ack(3, ack(3, ack(3, ack(2, ack(3, 0))))) -> ack(3, ack(3, ack(3, ack(2, ack(2, 1))))) -> ack(3, ack(3, ack(3, ack(2, ack(1, ack(2, 0)))))) -> ack(3, ack(3, ack(3, ack(2, ack(1, ack(1, 1)))))) -> ack(3, ack(3, ack(3, ack(2, ack(1, ack(0, ack(1, 0))))))) -> ack(3, ack(3, ack(3, ack(2, ack(1, ack(0, ack(0, 1))))))) -> ack(3, ack(3, ack(3, ack(2, ack(1, ack(0, 2)))))) -> ack(3, ack(3, ack(3, ack(2, ack(1, 3))))) -> ack(3, ack(3, ack(3, ack(2, ack(0, ack(1, 2)))))) -> ack(3, ack(3, ack(3, ack(2, ack(0, ack(0, ack(1, 1))))))) -> ack(3, ack(3, ack(3, ack(2, ack(0, ack(0, ack(0, ack(1, 0)))))))) -> ack(3, ack(3, ack(3, ack(2, ack(0, ack(0, ack(0, ack(0, 1)))))))) -> ack(3, ack(3, ack(3, ack(2, ack(0, ack(0, ack(0, 2)))))) -> ack(3, ack(3, ack(3, ack(2, ack(0, ack(0, 3))))) -> ack(3, ack(3, ack(3, ack(2, ack(0, 4))))) -> ack(3, ack(3, ack(3, ack(2, 5)))) -> ... ack(3, ack(3, ack(3, 13))) -> ... ack(3, ack(3, 65533)) -> ...

Teil 6 Rekursion und Iteration - Umwandlung rekursiver Algorithmen in iterative Algorithmen

Äquivalente Algorithmen Zur rekursiv definierten Fakultätsfunktion lässt sich leicht ein äquivalenter iterativer Berechnungsalgorithmus angeben: def fak(n): if n == 0: return 1 else: return n * fak(n-1) def fak(n): i = n erg = 1 while not i == 0: erg = erg * i i = i - 1 return erg Rekursion Iteration

Umwandlungsverfahren Ein allgemeines Umwandlungsverfahren erhält man, indem man die Reduktionsschritte bei der Auswertung von Termen simuliert. Dabei benutzt man zwei Stapel, um den aktuellen Berechnungszustand darzustellen. def ack(m, n): if m == 0: return n+1 else: if n == 0: return ack(m-1, 1) return ack(m-1, ack(m, n-1)) ack(2, 3) -> ack(1, ack(2, 2)) -> ack(1, ack(1, ack(2, 0))) -> ack(1, ack(1, ack(1, 1))) -> ack(1, ack(1, ack(0, ack(1, 0)))) -> ack(1, ack(1, ack(0, ack(0, 1)))) -> ack(1, ack(1, ack(0, 2))) -> ... Auswertung durch Reduktionsschritte Simulation mit Hilfe von Stapeln

Umwandlungsverfahren t s while t.size() > 0: e = t.top() t.pop() if type(e) == int: s.push(e) else: m = s.top() s.pop() n = s.top() if m == 0: t.push(n+1) if n == 0: t.push("a") t.push(m-1) t.push(1) t.push(m) t.push(n-1) def ack(m, n): if m == 0: return n+1 else: if n == 0: return ack(m-1, 1) return ack(m-1, ack(m, n-1))

Umwandlungsverfahren t s while t.size() > 0: e = t.top() t.pop() if type(e) == int: s.push(e) else: m = s.top() s.pop() n = s.top() if m == 0: t.push(n+1) if n == 0: t.push("a") t.push(m-1) t.push(1) t.push(m) t.push(n-1) def auswerten(term): t = Stapel() t.setStapel(term) s = Stapel() while t.size() > 0: # siehe links return s.top() def ack(m, n): term = [n, m, "a"] return auswerten(term) äquivalenter iterativerAlgorithmus def ack(m, n): if m == 0: return n+1 else: if n == 0: return ack(m-1, 1) return ack(m-1, ack(m, n-1)) rekursiver Algorithmus

Umwandlungsverfahren t s Beachte: Die iterative Ausführung rekursiver Algorithmen ist deshalb von besonderer Bedeutung, weil rekursive Algorithmen (derzeit) immer auf sequentiell arbeitenden Maschinen ausgeführt werden. Das Umwandlungsverfahren zeigt exemplarisch, dass eine solche iterative Ausführung immer möglich ist.

Übungen (siehe 9.6.1) Testen Sie die Implementierung des Umwandlungsverfahrens (siehe 9.6.1). Übertragen Sie das Umwandlungsverfahren auch auf die Funktion galton (siehe Aufgabe 2).

Teil 7 Rekursion und Iteration - Umwandlung iterativer Algorithmen in rekursive Algorithmen

Äquivalente Algorithmen Zur iterativ definierten Potenzfunktion lässt sich leicht ein äquivalenter rekursiver Berechnungsalgorithmus angeben: def pot(a, n): p = 1 while n > 0: p = p * a n = n - 1 return p def pot(a, n): if n == 0: return 1 else: return a * pot(a, n-1) Iteration Rekursion

Umwandlungsverfahren Ein allgemeines Umwandlungsverfahren erhält man, indem man die Auswertungsschritte bei der Abarbeitung des Algorithmus simuliert. def pot(a, n): p = 1 while n > 0: p = p * a n = n - 1 return p {a -> 2; n -> 3} p = 1 while n > 0: p = p * a n = n - 1 {a -> 2; n -> 3; p -> 1} {a -> 2; n -> 2; p -> 2} ... {a -> 2; n -> 0; p -> 8} Abarbeitung des Algorithmus

Umwandlungsverfahren Das folgende Ablaufprotokoll zeigt, wie die Daten mit Hilfe von Listen, Tupeln etc. dargestellt werden sollen. [('a', 2), ('n', 3)] [('=', 'p', 1), ('while', ('>', 'n', 0), [('=', 'p', ('*', 'p', 'a')), ('=', 'n', ('-', 'n', 1))])] [('a', 2), ('n', 3), ('p', 1)] [('while', ('>', 'n', 0), [('=', 'p', ('*', 'p', 'a')), ('=', 'n', ('-', 'n', 1))])] [('=', 'p', ('*', 'p', 'a')), ('=', 'n', ('-', 'n', 1)), ('while', ('>', 'n', 0), [('=', 'p', ('*', 'p', 'a')), ('=', 'n', ('-', 'n', 1))])] [('a', 2), ('n', 3), ('p', 2)] [('=', 'n', ('-', 'n', 1)), ('while', ('>', 'n', 0), [('=', 'p', ('*', 'p', 'a')), ('=', 'n', ('-', 'n', 1))])] ... [('a', 2), ('n', 0), ('p', 8)] [] {a -> 2; n -> 3} p = 1 while n > 0: p = p * a n = n - 1 {a -> 2; n -> 3; p -> 1} {a -> 2; n -> 3; p -> 2} ... {a -> 2; n -> 0; p -> 8}

Umwandlungsverfahren Zur Erzeugung des Ablaufprotokolls werden folgende Hilfsfunktionen benutzt: >>> VariablenWert('y', [('x', 4), ('y', 3), ('z', 7)]) 3 >>> VariablenWert('a', [('x', 4), ('y', 3), ('z', 7)]) '?' >>> NeuerZustand('y', 6, [('x', 4), ('y', 3), ('z', 7)]) [('x', 4), ('y', 6), ('z', 7)] >>> NeuerZustand('a', 0, [('x', 4), ('y', 3), ('z', 7)]) [('x', 4), ('y', 3), ('z', 7), ('a', 0)] >>> TermWert(('+', 'z', 4), [('x', 4), ('y', 3), ('z', 7)]) 11 >>> TermWert(('+', 'z', ('+', 'x', 'x')), [('x', 4), ('y', 3), ('z', 7)]) 15 >>> BooleWert(('>', 'x', 4), [('x', 4), ('y', 3), ('z', 7)]) False >>> BooleWert(('==', 'x', 4), [('x', 4), ('y', 3), ('z', 7)]) True

Umwandlungsverfahren Zur Erzeugung des Ablaufprotokolls werden folgende Hilfsfunktionen benutzt: >>> AnweisungenAusfuehren([('=', 'x', 2), ('if', ('>', 'x', 3), [('=', 'y', '0')], [('=', 'y', 1)])], []) [('x', 2), ('y', 1)] >>> AnweisungenAusfuehren([('while', ('>', 'u', 0), [('=', 'u', ('-', 'u', 1))])], [('u', 3)]) [('u', 0)] >>> AnweisungenAusfuehren([('=', 'p', 1), ('while', ('>', 'n', 0), [('=', 'p', ('*', 'p', 'a')), ('=', 'n', ('-', 'n', 1))])], [('a', 2), ('n', 3)]) [('a', 2), ('n', 0), ('p', 8)]

Umwandlungsverfahren def pot(a, n): p = 1 while n > 0: p = p * a n = n - 1 return p iterativer Algorithmus def potenz(a, n): return VariablenWert('p', \ AnweisungenAusfuehren(\ [\ ('=', 'p', 1), \ ('while', ('>', 'n', 0), \ ('=', 'p', ('*', 'p', 'a')), \ ('=', 'n', ('-', 'n', 1))\ ])\ ], \ [('a', a), ('n', n)])) äquivalenter rekursiver Algorithmus

Übungen (siehe 9.6.2) Testen Sie die Implementierung des Umwandlungsverfahrens (siehe 9.6.2). Übertragen Sie das Umwandlungsverfahren auch auf eine andere Definition der Potenzfunktion (siehe Aufgabe 1/3).