Click here to load reader

Problemlösen mit Rekursion

  • View
    41

  • Download
    1

Embed Size (px)

DESCRIPTION

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. Teil 1. - PowerPoint PPT Presentation

Text of Problemlösen mit Rekursion

  • Problemlsen mit RekursionKlaus Becker 2009

  • Problemlsen mit RekursionInhalte:Problemlsen durch ProblemreduktionSelbsthnliche FigurenRekursive Verarbeitung von ListenRekursive Verarbeitung natrlicher ZahlenRekursion und BerechnungsaufwandRekursion und Iteration

  • Teil 1Problemlsen durch Problemreduktion

  • Einstieg - Trme von HanoiEiner Geschichte zufolge soll im Tempel zu Benares - das ist eine "heilige Stadt" in Indien - ein Turm aus 64 goldenen, der Gre nach geordneten Scheiben stehen. Die Mnche des Tempels erhalten die Aufgabe, die Scheiben an einen anderen Ort zu bringen. Dabei mssen sie einige Regeln beachten: Es darf immer nur eine Scheibe transportiert werden. Scheiben knnen auf einem (einzigen) Hilfsstapel zwischenzeitlich abgelegt werden. Auch auf dem (teilweise abgebauten) Ausgangsturm knnen Scheiben zwischenzeitlich abgelegt werden. Es darf aber nie eine grere 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)AusgangszustandVersuchen Sie, einen Turm mit 5 Scheiben nach den vorgegebenen Regeln umzustapeln. Wenn das nicht klappt, dann versuchen Sie erst einmal, Trme mit 3 bzw. 4 Scheiben umzustapeln.ZielzustandBenutzen Sie Mnzen unterschiedlicher Gre oder ein Simulationsprogramm. z. B.: http://www.mpg-trier.de/d7/prog/hanoi/hanoi.htm

  • Einstieg - Aufgabe (siehe 9.1.1)Ausgangszustandberlegen Sie sich auch eine Strategie, mit der man Trme mit 6, 7, ... Scheiben umstapeln kann. Zielzustand

  • Lsungsideetransportiere einen 4-Scheiben-Turm von A ber C nach Btransportiere eine Scheibe von A nach C transportiere einen 4-Scheiben-Turm von B ber A nach C AusgangszustandZielzustandZwischenzustandZwischenzustandtransportiere einen 5-Scheiben-Turm von A ber B nach C

  • Verallgemeinerungtransportiere einen (n-1)-Scheiben-Turm von X ber Z nach Ytransportiere eine Scheibe von X nach Ztransportiere einen (n-1)-Scheiben-Turm von Y ber X nach ZAusgangszustandZielzustandZwischenzustandZwischenzustandtransportiere einen n-Scheiben-Turm von X ber Y nach Z

  • AlgorithmusAlgorithmus: 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: transportiere eine Scheibe von X nach Z

  • Rekursive ProblemreduktionRekursive Problemreduktion ist eine Problemlsestrategie, bei der ein Problem auf ein strukturgleiches Problem (in verkleinerter Form) zurckgefhrt wird.Ein rekursiver Algorithmus ruft sich (eventuell ber Umwege) selbst auf und nutzt sich so selbst zur Beschreibung der Lsung des gegebenen Problems.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: transportiere eine Scheibe von X nach Z Um Rekursion als Problemlsestrategie nutzen zu knnen, bentigt man ein Ausfhrsystem, das in der Lage ist, rekursive Algorithmen wiederholt aufzurufen und auf diese Weise die eigentliche Lsung zu generieren.

  • Ausfhrung des AlgorithmusAlgorithmus: 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: transportiere eine Scheibe von X nach Z 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 CAusfhrungstiefe: 1

  • Ausfhrung des AlgorithmusAlgorithmus: 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: transportiere eine Scheibe von X nach Z 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 transportiere einen 1-Scheiben-Turm von A ber B nach CAusfhrungstiefe: 2

  • Ausfhrung des AlgorithmusAlgorithmus: 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: transportiere eine Scheibe von X nach Z 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 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 A transportiere eine Scheibe von B nach C transportiere einen 1-Scheiben-Turm von A ber B nach C: transportiere eine Scheibe von A nach CAusfhrungstiefe: 3

  • Ausfhrung des Algorithmustransportiere 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 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 A transportiere eine Scheibe von B nach C transportiere einen 1-Scheiben-Turm von A ber B nach C: transportiere eine Scheibe von A nach CBasisaktionen

  • Implementierung in Pythondef 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: print "transportiere eine Scheibe von ", x, " nach ", zAlgorithmus: 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: transportiere eine Scheibe von X nach Z AlgorithmusPython-Programm

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

  • Teil 2Selbsthnliche Figuren

  • Einstieg - Selbsthnliche FigurEine Figur ist selbsthnlich, wenn sie sich in Teile zerlegen lsst, die zur ihr hnlich sind.

  • Einstieg - Selbsthnliche FigurEine Figur ist selbsthnlich, wenn sie sich in Teile zerlegen lsst, die zur ihr hnlich sind.zeichne_Baum(200): gehe_vorwaerts(200) drehe_dich_nach_rechts(45) zeichne_Baum(100) drehe_dich_nach_links(90) zeichne_Baum(100) drehe_dich_nach_rechts(45) 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) zeichne_Baum(x/2) drehe_dich_nach_rechts(45) gehe_rueckwaerts(x) rekursive Problemreduktionrekursiver Algorithmus

  • Exkurs - Turtle-GrafikTurtle-Grafik basiert auf der Vorstellung, dass eine Schildkrte mit bestimmten Anweisungen auf einer Zeichenflche bewegt wird und dass die Schildkrte dabei eine Spur hinterlsst.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-AlgorithmusTurtle-Befehlevorwaerts(100)

  • Exkurs - Turtle-Grafik in PythonTurtle-Grafik basiert auf der Vorstellung, dass eine Schildkrte mit bestimmten Anweisungen auf einer Zeichenflche bewegt wird und dass die Schildkrte dabei eine Spur hinterlsst.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-ProgrammTurtle-Klasse# -*- coding: iso-8859-1 -*-from turtle import *# Deklaration einer Zeichenprozedurdef quadrat(laenge): for i in range(4): t.forward(laenge) t.left(90)# Erzeugung eines Turtle-Objektst = Turtle()# Test der Zeichenprozedurquadrat(100) t.forward(100)

  • Exkurs - Turtle-Grafik in Python# -*- coding: iso-8859-1 -*-from turtle import *# Deklaration einer Zeichenprozedurdef baum(stamm): if stamm >= 2: t.forward(stamm) t.right(45) baum(stamm/2) t.left(90) baum(stamm/2) t.right(45) t.backward(stamm)# Erzeugung eines Turtle-Objektst = Turtle()# Test der Zeichenprozedurt.left(90)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) zeichne_Baum(x/2) drehe_dich_nach_rechts(45) gehe_rueckwaerts(x)

  • bungen (siehe 9.2.3)Whlen Sie eine der folgenden selbsthnlichen 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)Whlen Sie eine der folgenden selbsthnlichen 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)Whlen Sie eine der folgenden selbsthnlichen 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)Whlen Sie eine der folgenden selbsthnlichen 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)Whlen Sie eine der folgenden selbsthnlichen 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)Whlen Sie eine der folgenden selbsthnlichen Figuren aus. Entwickeln Sie mit Hilfe einer rekursive Problemreduktion einen rekursiven Algorithmus zum Zeichnen der Figur. Testen Sie den Algorithmus mit einer Python-Implementierung.

  • Teil 3Rekursive Verarbeitung von Listen

  • Einstieg - Geschachtelte ListenEine Gsteliste soll mit einem Programm verwaltet und verarbeitet werden.def ausgabe(liste): i = 0 while i < len(liste): element = liste[i] print element i = i + 1def ausgabe(liste): if len(liste) == 0: pass else: erstesElement = liste[0] restListe = liste[1:] print erstesElement ausgabe(restListe)gaeste = ["Ursula", "Winfried", "Ulrike", "Klaus", ...]# Testausgabe(gaeste)rekursiviterativ

  • Einstieg - Geschachtelte ListenEine Gsteliste soll mit einem Programm verwaltet und verarbeitet werden.

    ?

    gaeste = \ [ \ ["Ursula", "Winfried"], \ ["Ulrike", "Klaus"], \ ["Christiane", "Tim"], \ ["Andreas"], \ ["Ulrike", "Peter", ["Kea", "Lena", "Paula"]], \ ... ]# Testausgabe(gaeste)iterativdef ausgabe(liste): if len(liste) == 0: pass else: erstesElement = liste[0] restListe = liste[1:] if type(erstesElement) == list: ausgabe(erstesElement) else: print erstesElement ausgabe(restListe)rekursiv

  • Einstieg - Geschachtelte Listenausgabe([["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([]) pass ausgabe([["Christiane", "Tim"], ...]) ...def ausgabe(liste): if len(liste) == 0: pass else: erstesElement = liste[0] restListe = liste[1:] if type(erstesElement) == list: ausgabe(erstesElement) else: print erstesElement ausgabe(restListe)rekursiver AlgorithmusAusfhrung

  • Liste als rekursive DatenstrukturEine 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:] if type(erstesElement) == list: ausgabe(erstesElement) else: print erstesElement ausgabe(restListe)def ausgabe(liste): if len(liste) == 0: # liste == [] pass else: # liste == [erstesElement] + restListe erstesElement = liste[0] restListe = liste[1:] print erstesElement ausgabe(restListe)

  • Entwicklung rekursiver AlgorithmenProblem: Es soll gezhlt werden, wie oft ein Element in einer Liste vorkommt.anzahl('b', []) -> 0Reduktionsanfang: Lse das Problem direktRekursive Problemreduktion: Reduziere des Problems auf ein entsprechendes, aber verkleinertes Problem.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: Lse ein entsprechendes ProblemFall 2: Bearbeite eine nicht-leere ListeFall 1: Bearbeite eine leere Liste

  • Entwicklung rekursiver AlgorithmenProblem: Es soll gezhlt werden, wie oft ein Element in einer Liste vorkommt.anzahl('b', []) -> 0

    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:])) else: return anzahl(element, liste[1:])(rekursive) Reduktionsschritte(rekursive) ReduktionsregelnRekursive Problemreduktion: Reduziere des Problems auf ein entsprechendes, aber verkleinertes Problem.

  • Entwicklung rekursiver AlgorithmenProblem: Es soll gezhlt 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:])) else: 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 ObjekteIn den folgenden Aufgaben (siehe 9.3.4) geht es um die Verwaltung und Verarbeitung geometrischer Objekte. Wir betrachten vereinfachend nur geometrische Objekte, die aus Streckenzgen 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.

  • Teil 4Rekursive Verarbeitung natrlicher Zahlen

  • Einstieg - Wege im Galton-BrettEin Galton-Brett besteht aus Stben, die in Reihen untereinander versetzt angeordnet sind. Wenn man eine Kugel ein solches Galton-Brett herunterrollen lsst, 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 Stbe in der Abbildung oben sind bereits mit Stab-Koordinaten versehen. Mit diesen Koordinaten knnte man einen mglichen 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 fr alle Stbe 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). Begrnden Sie die unten formulierten Eigenschaften der Funktion galton.galton(n, 0) -> 1galton(n, n) -> 1galton(m, n) -> galton(m-1, n-1) + galton(m-1, n), falls m > 0 und 0 < n < m gilt.galton(2, 0)

  • 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 0 else: if n == 0: return 1 else: 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 else: if n == 0: return 1 else: return (galton(m-1, n-1) + galton(m-1, n))def galton(m, n): if m < n: return None else: if (n == 0) or (m == n): return 1 else: return (galton(m-1, n-1) + galton(m-1, n))

  • Rekursive Struktur natrlicher ZahlenProblem: Die Summe der ersten n natrlichen Zahlen soll berechnet werden.summe(0) -> 0Reduktionsanfang: Lse das Problem direktRekursive Problemreduktion: Reduziere des Problems auf ein entsprechendes, aber verkleinertes Problem.summe(5) -> 5 + summe(4)Rekursionsschritt: Lse ein entsprechendes ProblemFall 2: Bearbeite den Nachfolger einer natrlichen ZahlFall 1: Bearbeite die Zahl 0.Eine natrliche Zahl ist entweder eine Null oder Nachfolger einer natrlichen Zahl.

  • Entwicklung rekursiver Algorithmensumme(0) -> 0

    summe(5) -> 5 + summe(4)def summe(zahl): if zahl == 0: return 0 else: return zahl + summe(zahl-1)(rekursive) Reduktionsschritte(rekursive) ReduktionsregelnRekursive Problemreduktion: Reduziere des Problems auf ein entsprechendes, aber verkleinertes Problem.Problem: Die Summe der ersten n natrlichen Zahlen soll berechnet werden.

  • Entwicklung rekursiver Algorithmensumme(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 ->15Reduktionskette(rekursive) Reduktionsregeln>>> summe(5)15Problem: Die Summe der ersten n natrlichen Zahlen soll berechnet werden.def summe(zahl): if zahl == 0: return 0 else: return zahl + summe(zahl-1)

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

  • Fallstudie - natrliche ZahlenOperationen auf natrlichen Zahlen lassen sich alle aus einer einzigen Grundoperationen entwickeln. Man bentigt hierzu nur die Nachfolger-Operation s: N -> N, die jeder natrlichen Zahl n ihren Nachfolger s(n) zuordnet.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)))add(x,0) -> xadd(x,s(y)) -> s(add(x,y))(rekursive) ReduktionsregelnImplementierung in PythonBearbeiten Sie die Aufgaben aus Abschnitt 9.4.4.

  • Teil 5Rekursion und Berechnungsaufwand

  • Einstieg - Wege im Galton-BrettWarum handelt es sich hier um ein ineffizientes Berechnungsverfahren?def galton(m, n): print "galton(", m, ",", n, ")" if m < n: return None else: if (n == 0) or (m == n): return 1 else: return (galton(m-1, n-1) + galton(m-1, n))>>> 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 , 1 )galton( 1 , 0 )galton( 1 , 1 )galton( 2 , 2 )galton( 4 , 3 )galton( 3 , 2 )galton( 2 , 1 )galton( 1 , 0 )galton( 1 , 1 )galton( 2 , 2 )galton( 3 , 3 )10

  • 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 knnen. Heute gibt es eine ganze Reihe von Funktionen, die als Ackermannfunktion bezeichnet werden. Diese weisen alle ein hnliches Bildungsgesetz wie die ursprngliche Ackermannfunktion auf und haben auch ein hnliches Wachstumsverhalten." (wikipedia)ack(0, y) -> y+1 ack(x, 0) -> ack(x-1, 1), falls x > 0ack(x, y) -> ack(x-1, ack(x, y-1)), falls y > 0

  • Auswertung der Ackermann-FunktionSetzen Sie die Reduktionskette einige Schritte weiter fort. Wollen Sie es zu Ende rechnen?ack(3, 2) -> ack(2, ack(3, 1)) ->ack(2, ack(2, ack(3, 0))) ->ack(2, ack(2, ack(2, 1))) ->

    ack(0, y) -> y+1 ack(x, 0) -> ack(x-1, 1), falls x > 0ack(x, y) -> ack(x-1, ack(x, y-1)), falls y > 0

  • Implementierung d. Ackermann-Funkt.ack(0, y) -> y+1 ack(x, 0) -> ack(x-1, 1), falls x > 0ack(x, y) -> ack(x-1, ack(x, y-1)), falls y > 0Implementieren 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 fllt auf?

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

  • BerechnungsaufwandWarum stt 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 6Rekursion und Iteration - Umwandlung rekursiver Algorithmen in iterative Algorithmen

  • quivalente AlgorithmenZur rekursiv definierten Fakulttsfunktion lsst 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 ergRekursionIteration

  • UmwandlungsverfahrenEin allgemeines Umwandlungsverfahren erhlt 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) else: 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 ReduktionsschritteSimulation mit Hilfe von Stapeln

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

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

  • UmwandlungsverfahrentsBeachte: Die iterative Ausfhrung rekursiver Algorithmen ist deshalb von besonderer Bedeutung, weil rekursive Algorithmen (derzeit) immer auf sequentiell arbeitenden Maschinen ausgefhrt werden. Das Umwandlungsverfahren zeigt exemplarisch, dass eine solche iterative Ausfhrung immer mglich 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 7Rekursion und Iteration - Umwandlung iterativer Algorithmen in rekursive Algorithmen

  • quivalente AlgorithmenZur iterativ definierten Potenzfunktion lsst sich leicht ein quivalenter rekursiver Berechnungsalgorithmus angeben:def pot(a, n): p = 1 while n > 0: p = p * a n = n - 1 return pdef pot(a, n): if n == 0: return 1 else: return a * pot(a, n-1)IterationRekursion

  • UmwandlungsverfahrenEin allgemeines Umwandlungsverfahren erhlt 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 = 1while n > 0: p = p * a n = n - 1{a -> 2; n -> 3; p -> 1}while n > 0: p = p * a n = n - 1{a -> 2; n -> 3; p -> 1}p = p * an = n - 1while n > 0: p = p * a n = n - 1{a -> 2; n -> 2; p -> 2}...{a -> 2; n -> 0; p -> 8}Abarbeitung des Algorithmus

  • UmwandlungsverfahrenDas folgende Ablaufprotokoll zeigt, wie die Daten mit Hilfe von Listen, Tupeln etc. dargestellt werden sollen.{a -> 2; n -> 3}p = 1while n > 0: p = p * a n = n - 1{a -> 2; n -> 3; p -> 1}while n > 0: p = p * a n = n - 1{a -> 2; n -> 3; p -> 1}p = p * an = n - 1while n > 0: p = p * a n = n - 1{a -> 2; n -> 3; p -> 2}...{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)][('while', ('>', 'n', 0), [('=', 'p', ('*', 'p', 'a')), ('=', 'n', ('-', 'n', 1))])]

    [('a', 2), ('n', 3), ('p', 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)][]

  • UmwandlungsverfahrenZur 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

  • UmwandlungsverfahrenZur 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)]

  • Umwandlungsverfahrendef potenz(a, n): return VariablenWert('p', \ AnweisungenAusfuehren(\ [\ ('=', 'p', 1), \ ('while', ('>', 'n', 0), \ [\ ('=', 'p', ('*', 'p', 'a')), \ ('=', 'n', ('-', 'n', 1))\ ])\ ], \ [('a', a), ('n', n)]))def pot(a, n): p = 1 while n > 0: p = p * a n = n - 1 return piterativer Algorithmusquivalenter 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).