Grundlagen der Programmierung Algorithmen und Datenstrukturen Die Inhalte der Vorlesung wurden primär auf Basis der angegebenen Literatur erstellt. Darüber hinaus sind ausgewählte Teile in Anlehnung an die Vorlesung von Prof. Dr. Faustmann (ebenfalls HWR Berlin) erstellt worden. Für die Bereitstellung dieses Vorlesungsmaterials möchte ich mich an dieser Stelle noch einmal recht herzlich bedanken. 10.01.2012 Prof. Dr. Andreas Schmietendorf 1
Überblick zur Rekursion 10.01.2012 Prof. Dr. Andreas Schmietendorf 2
Überblick zur Rekursion Definition der Rekursion: Die Rekursion ist ein wichtiges Konzept der Mathematik und Informatik Selbstaufruf & Abbruchbedingung Ein Unterprogramm heißt rekursiv, wenn es sich direkt oder indirekt selbst aufruft. - direkte Rekursion eine rekursive Funktion ruft sich selbst auf - indirekte Rekursion eine Funktion A ruft zunächst eine Funktion B auf, die wiederum A aufruft In der Programmierung besteht eine rekursive Lösung eines Problems darin, dass Teilprobleme gelöst und zu einer Gesamtlösung verknüpft werden. 10.01.2012 Prof. Dr. Andreas Schmietendorf 3
Überblick zur Rekursion Es gilt, dass alle iterativ lösbaren 1 Probleme ebenso durch Rekursion lösbar sind. Es existieren Programmiersprachen, die keine Schleifen kennen und nur die Rekursion als Ausdruck der Wiederholung nutzen. (z.b. Prolog, Lisp oder Logo). Rekursion kann meist mit Hilfe von Iteration simuliert werden. Oft sind rekursive Lösungen einfacher zu verstehen, verbrauchen aber für die Abarbeitung der Rekursion mehr Speicherplatz. Es stellt sich jeweils die Frage, wie weit die beiden Ansätze austauschbar sind und jeweils Vorteile bieten. 1 also durch Schleifenkonstrukte zu beschreibende Algorithmen 10.01.2012 Prof. Dr. Andreas Schmietendorf 4
Überblick zur Rekursion Anwendungsbereiche für die Rekursion: - rekursive Definition binärer Bäume - komplexe Entscheidungsprobleme der künstlichen Intelligenz - Sortier- und Suchalgorithmen - vielfältige mathematische Probleme - rekursive Bearbeitung verketteter Listen und Bäume Bewertung rekursiver Algorithmen : - führen zumeist nicht zur Verkleinerung der Codegröße - benötigen häufig mehr Speicher als das iterative Pendant - laufen meist langsamer als ihre iterativen Gegenstücke - Bieten aber ein gutes Werkzeug zum Lösen von Problemen 10.01.2012 Prof. Dr. Andreas Schmietendorf 5
Überblick zur Rekursion Übung: Welche Ausgabe wird durch den Aufruf des folgenden Programmfragments erzeugt? - Schreiben Sie das Ergebnis zunächst auf Papier! - Testen Sie das Fragment innerhalb eines ausführbaren Programms! Was verstehen Sie unter rekursiven Abstieg bzw. Aufstieg? 10.01.2012 Prof. Dr. Andreas Schmietendorf 6
Überblick zur Rekursion Die Fakultät ist das Produkt der ersten n natürlichen Zahlen: n! Iterative Lösung: Rekursive Lösung: int fakiterativ(int n){ } int erg = 1; for(int i=1; i<=n; i++){ } erg *= i; return erg; int fakrekursiv(int n){ if (n<=1){ return 1; else return n * fakrekursiv(n-1); Nachteil der rekursiven Lösung: Zusätzlicher Verbrauch von Speicher, da Aufrufe auf dem Stapel abgelegt werden. Die Speicherkomplexität ist linear, da je nach Größe des Parameters der benötigte Speicher wächst. 10.01.2012 Prof. Dr. Andreas Schmietendorf 7 }
Überblick zur Rekursion Kriterien zum Verständnis der Rekursion: Verwendung von Unterprogrammen (in Java Methoden) - Mechanismus des Aufrufs eines Unterprogramms - Mechanismus des Rücksprungs aus dem Unterprogramm Begriff der Aktivierungsliste mit den Bestanteilen - Belegung der Parameter der aufgerufenen Methoden - Bei Beendigung wird ggf. ein Rückgabewert geliefert (optional) - Adresse wohin nach Beendigung der Methode zurückgekehrt werden soll Rekursion ist in einer Programmiersprache möglich, wenn für jede Iteration einer Methode eine eindeutige Aktivierungsliste (Aufrufparameter und Rücksprungsadresse auch Programmstackverwaltung) gespeichert wird. 10.01.2012 Prof. Dr. Andreas Schmietendorf 8
Überblick zur Rekursion Aufrufbaum zur rekursiven Berechnung von 3! In Anlehnung an: Sanchez, J.; Canton, M.P.: Java 2 Wochenend Crashkurs, mitip-verlag, ISBN 3-8266-0769-4 10.01.2012 Prof. Dr. Andreas Schmietendorf 9
Überblick zur Rekursion Die richtige Durchführung dieser Berechnung organisiert der Compiler aus dem Text der rekursiven Definition. Der Programmierer muss sich nur darum kümmern, dass die entstehenden rekursiven Aufrufe immer einfacher werden und schließlich auf einen nichtrekursiven Fall führen. Bem.: Beim Beispiel der Fakultät führt die Berechnung von 3! zu den Aufrufen von fakrekursiv(3), fakrekursiv(2), fakrekursiv(1) und schließlich mit fakrekursiv(0) zu einem nicht rekursiven Aufruf. Quelle: Gumm, H. P.; Sommer, M.: Einführung in die Informatik, 8. Auflage, Oldenbourg Verlag, München 2009 10.01.2012 Prof. Dr. Andreas Schmietendorf 10
Überblick zur Rekursion Übung: Implementieren Sie den Euklidischen Algorithmus mit Hilfe einer rekursiven Methode static int ggt(int a, int b). Bem.: Eine Zahl t teilt sowohl x als auch y nur dann, wenn t sowohl y als auch x mod y teilt, weil x gleich x mod y plus einem Vielfachen von y ist. Quelle: Quelle: Sedgewick, R.: Algorithmen in Java 3. Auflage, Pearson Studium, Addison-Wesley, München,, 2003 10.01.2012 Prof. Dr. Andreas Schmietendorf 11
Überblick zur Rekursion a 212 = 3 x 66 + 14 b Beispiel: ggt(212, 66) 66 = 4 x 14 + 10 14 = 1 x 10 + 4 10 = 2 x 4 + 2 4 = 2 x 2 + 0 Rekursive Formulierung des mathematischen Problems zur Berechnung des ggt zweier Zahlen. Bei jedem Zeilenwechsel wird ggt(a,b) durch ggt(b,a mod b) ersetzt. Das bisherige b wird zum a bzw. das Ergebnis von a mod b zum b des folgenden Aufrufs. Der Abbruch erfolgt im Falle b = 0. 2 = 0 x 0 + 2 Ergebnis: ggt(212, 66) = 2 10.01.2012 Prof. Dr. Andreas Schmietendorf 12
Überblick zur Rekursion Beispiele zur rekursiven Lösung des Euklidischen Algorithmus: 10.01.2012 Prof. Dr. Andreas Schmietendorf 13
10.01.2012 Prof. Dr. Andreas Schmietendorf 14
Ein einführendes Beispiel: Anzeige der Ziffern einer Integerzahl in Form eines vertikalen Stapels und Konvertierung in das Binärformat Beispiel des vertikalen Stapels für die Zahl 255: 2 5 5 Beispiel der Binären Darstellung für die Zahl 255: 1111 1111 Gesucht rekursiver Algorithmus? 10.01.2012 Prof. Dr. Andreas Schmietendorf 15
10.01.2012 Prof. Dr. Andreas Schmietendorf 16
Rekursionen können oft durch Wiederholungen ersetzt werden. Rekursive Lösungen sind zwar oft einfach zu verstehen, zur Laufzeit jedoch manchmal unwirtschaftlich. Ein Beispiel für diese Problematik ist die Ermittlung der Fibonacci- Zahlen: f 0 = 0 f 1 = 1 f n = f n-1 + f n-2 für n>=2 Die ersten vierzehn Fibonacci-Zahlen: 10.01.2012 Prof. Dr. Andreas Schmietendorf 17
Übung: Programmieren Sie eine Funktion int fibonaccirek(int n), die die n-te Fibonacci-Zahl auf rekursive Weise berechnet. Programmieren Sie eine Funktion int fibonacciiter(int n), die die n-te Fibonacci-Zahl auf iterative Weise berechnet. Erstellen Sie einen entsprechenden Aufrufbaum (z.b. für n = 4) und ermitteln Sie die Zeitkomplexität O der beiden Algorithmen Vergleichen Sie ihre theoretisch ermittelten Ergebnisse mit der Vermessung beider Algorithmen für wachsende n - long startmesswert = System.currentTimeMillis(); - long endmesswert = System.currentTimeMillis(); - long laufzeit = startmesswert endmesswert; 10.01.2012 Prof. Dr. Andreas Schmietendorf 18
Rekursive Lösung für Fibonacci-Zahlen: 10.01.2012 Prof. Dr. Andreas Schmietendorf 19
Iterative Lösung für Fibonacci-Zahlen: 10.01.2012 Prof. Dr. Andreas Schmietendorf 20
Reduktion der Problemgröße 10.01.2012 Prof. Dr. Andreas Schmietendorf 21
Durch Induktion zu lösende Probleme können per Rekursion bearbeitet werden. Um einen gegebenen Satz für eine beliebige natürliche Zahl zu beweisen, führt man zwei Schritte durch: - 1. Einen (trivialen) Beweis für n=0 oder n=1. - 2. Einen Beweis für n+1 unter der Annahme, dass der Satz für n gilt. Ein rekursiver Algorithmus nutzt diesen Zusammenhang aus: - 1. Reduktion des Problems auf ein Teilproblem geringeren Ausmaßes - 2. Direkte Lösung des zweiten Teilproblems Beispiel: Türme von Hanoi (siehe Übung) 10.01.2012 Prof. Dr. Andreas Schmietendorf 22
Türme von Hanoi: Gegeben sind 3 Pfähle und N Scheiben die sich auf die Pfähle stecken lassen. Die Scheiben unterscheiden sich in der Größe und stecken zu Beginn des Spiels auf einem der Pfähle. Die größte Scheibe N liegt ganz unten und die kleinste Scheibe 1 ganz oben. Aufgabe ist es den Stapel zur rechten Position zu ziehen, dabei gilt: - Es darf jeweils nur eine Scheibe gezogen werden - Keine Scheibe darf auf einer kleineren liegen 10.01.2012 Prof. Dr. Andreas Schmietendorf 23
1. Überlegung: - Rollen der Stäbe A und C vertauschen (d.h. C als Zwischenlager) - Turm von n-1 Scheiben von A nach B transportieren - Unterste Scheibe kann zum Schluss von A nach C gebracht werden 2. Überlegung: - Rollen der Stäbe A und C vertauschen (d.h. A als Zwischenlager) - Turm von n-1 Scheiben von B nach C transportieren - Unterste Scheibe kann zum Schluss von B nach A gebracht werden 10.01.2012 Prof. Dr. Andreas Schmietendorf 24
10.01.2012 Prof. Dr. Andreas Schmietendorf 25
Quelle: http://www.mathematik.ch/spiele/hanoi_mit_grafik/ 10.01.2012 Prof. Dr. Andreas Schmietendorf 26
Übung: Verwenden Sie das im Internet zur Verfügung gestellte Applet zur manuellen Lösung des Problems der Türme von Hanoi. - 3 Scheiben als Ausgangsbasis Anzahl benötigter Züge? - 4 Scheiben als Ausgangsbasis Anzahl benötigter Züge? - 5 Scheiben als Ausgangsbasis Anzahl benötigter Züge? Beobachten Sie die animierten Lösungen beschreiben Sie den mathematischen Zusammenhang zwischen der Anzahl Schreiben und der minimalen Anzahl von benötigten Zügen! 10.01.2012 Prof. Dr. Andreas Schmietendorf 27
Übung: Realisieren Sie ein Programm, das das Problem der Türme von Hanoi löst. Ihre Funktion versetzeturm sollte als Parameter die Anzahl der Scheiben und den Start- und Endeplatz (möglich sind A, B und C) erhalten. Bsp: versetzeturm( 3, "A", "B", "C" ); bewegt 3 Scheiben von Stab A über Stab B auf den Stab C. Geben Sie die Einzeloperation (z.b. Eine Scheibe von A nach B legen) als Textausgabe aus. 10.01.2012 Prof. Dr. Andreas Schmietendorf 28
Quelle: Ullenboom, C.: Java ist auch eine Insel, http://www.galileocomputing.de 10.01.2012 Prof. Dr. Andreas Schmietendorf 29
Backtracking 10.01.2012 Prof. Dr. Andreas Schmietendorf 30
Übung optional: Ein klassisches Problem für die Verwendung von Rekursion ist das Acht-Damen-Problem: - Acht Damen sind auf einem Schachbrett so auszustellen, daß keine der Damen eine andere bedroht. - Schachbrett 64 Felder mit 8 Spalten und 8 Zeilen - Bedrohung gemäß den Schachregeln (gleiche Spalte, Zeile oder linke bzw. rechte Diagonale) Bedingung kann nur erfüllt werden, wenn jede Linie genau eine Damen enthält! 10.01.2012 Prof. Dr. Andreas Schmietendorf 31
Hinweis Acht-Damen-Problem: - Für das Acht-Damen-Problem existieren 92 Lösungen - Backtracking-Algorithmus (Lösungsbaum) Schrittweise Lösungssuche Nicht erfolgreiche Ansätze verwerfen Fortsetzung der Lösungssuche an einer vorherigen Stelle 10.01.2012 Prof. Dr. Andreas Schmietendorf 32