Java Rekursion Dr. Werner Struckmann / Stephan Mielke, Jakob Garbe, 11.10.2016 Technische Universität Braunschweig, IPS
Überblick Einleitung Beispiele 11.10.2016 Dr. Werner Struckmann / Stephan Mielke, Jakob Garbe Seite 2
Rekursion Rekursion... ist ein wichtiges Prinzip bei der Formulierung von Algorithmen. Es beschreibt die wiederholte Anwendung des gleichen Berechnungsmusters, allerdings i.d.r. auf immer einfachere Daten. Definition Ein rekursives Programm ist ein Programm, das sich selbst aufruft. Meist enthält es eine Abbruchbedingung zur Beendigung der Rekursion. 11.10.2016 Dr. Werner Struckmann / Stephan Mielke, Jakob Garbe Seite 3
Rekursion Bisher wurden Wiederholungen durch Schleifen gelöst Aber nicht alle Probleme lassen sich nur mit Schleifenlösen Außerdem viele Algorithmen benutzen das divide and conquer-prinzip Fakultät n! = n (n 1)... 2 1 Potenzieren a n = a n 1 a, a 0 = 1 Fibonacci-Funktion, Binomialkoeffzient, ggt, mod Such- und Sortierprobleme (z.b. in AuD)... 11.10.2016 Dr. Werner Struckmann / Stephan Mielke, Jakob Garbe Seite 4
Die Türme von Hanoi Gegeben: 3 Stäbe A, B, C n Scheiben unterschiedlicher Größe Beginn: Scheiben der Größe nach geordnet auf A Ziel: Verschiebe Scheiben von A nach C über B Scheiben einzeln versetzt Versetzen nur auf größere Scheiben oder den leere Stapel A B C Initial step A B C 11.10.2016 Dr. Werner Struckmann / Stephan Mielke, Jakob Garbe Seite 5
Die Türme von Hanoi Idee Mit dem Prinzip divide and conquer n = 1 Bewege Scheibe von A nach C n > 1 Bewege (n 1) Scheiben von A nach B über C Bewege letzte Scheibe von A nach C Transportiere (n 1) Scheiben von B nach C via A 11.10.2016 Dr. Werner Struckmann / Stephan Mielke, Jakob Garbe Seite 6
Die Türme von Hanoi Iterativ public s t a t i c void main ( String args [ ] ) { i n t N = 3; i n t nummoves, second = 0, third, pos2, pos3, j, i = 1; int [ ] l o c a t i o n s = new int [N + 2 ] ; for ( j = 0; j < N; j ++) { l o c a t i o n s [ i ] = 0 ; } locations [N + 1] = 2; nummoves = 1; for ( i = 1; i <= N; i ++) { nummoves = 2 ; } nummoves = 1; for ( i = 1; i <= nummoves ; i ++) { i f ( i % 2 == 1) { second = l o c a t i o n s [ 1 ] ; locations [ 1 ] = ( locations [ 1 ] + 1) % 3; System. out. p r i n t l n ( "Move disc 1 to " + ( char ) ( A + l o c a t i o n s [ 1 ] ) ) ; } else { t h i r d = 3 second l o c a t i o n s [ 1 ] ; pos2 = N + 1; for ( j = N + 1; j >= 2; j ) { i f ( l o c a t i o n s [ j ] == second ) { pos2 = j ; } } pos3 = N + 1; for ( j = N + 1; j >= 2; j ) { i f ( l o c a t i o n s [ j ] == t h i r d ) { pos3 = j ; } } System. out. p r i n t ( "Move disc " ) ; i f ( pos2 < pos3 ) { System. out. p r i n t l n ( pos2 + " to " + ( char ) ( A + t h i r d ) ) ; locations [ pos2 ] = third ; } else { System. out. p r i n t l n ( pos3 + " to " + ( char ) ( A + second ) ) ; locations [ pos3 ] = second ; } } } }
Die Türme von Hanoi Rekursiv n = 1 Bewege Scheibe von A nach C n > 1 Bewege (n 1) Scheiben von A nach B über C Bewege letzte Scheibe von A nach C Transportiere (n 1) Scheiben von B nach C via A. static void move( int n, char from, char to, char via) { if (n == 1) { System. out. println(" Move disk from pole " + from + " to pole " + to); } else { move(n - 1, from, via, to); move(1, from, to, via); move(n - 1, via, to, from); } } public static void main( String[] args) { move(4, A, C, B ); }
Klassifikation rekursiver Situationen Rekursive Definitionen umfassen (i.d.r.) mindestens 2 Dinge: Basisfall (Abbruch der Rekursion) Rekursionsschritt (rekursive Definition) Was ist was? public static int fak( int n) { if (n <= 1) { return 1; } return n * fak(n - 1); } 11.10.2016 Dr. Werner Struckmann / Stephan Mielke, Jakob Garbe Seite 9
Klassifikation rekursiver Situationen Rekursive Definitionen umfassen (i.d.r.) mindestens 2 Fälle: Basisfall (Abbruch der Rekursion) Rekursionsschritt (rekursive Definition) Was ist was? static void move( int n, char from, char to, char via) { if (n == 1) { System. out. println(" Move disk from pole " + from + " to pole " + to); } else { move(n - 1, from, via, to); move(1, from, to, via); move(n - 1, via, to, from); } } 11.10.2016 Dr. Werner Struckmann / Stephan Mielke, Jakob Garbe Seite 10
Vor- und Nachteile Vorteile: Mathematische Definition divide and conquer-prinzip Leichter lesbar und verständlicher für den Menschen Fehler bleiben lokal leichteres Debuggen Nachteile: Fehlendes Verständnis führt zur Endlosrekursion Auch bei korrekter Arbeitsweise kann ein Stack Overflow passieren Horror für die CPU! (Erklärung kommt gleich) 11.10.2016 Dr. Werner Struckmann / Stephan Mielke, Jakob Garbe Seite 11
Horror für die CPU Bei jedem Aufruf... Erstellen einen Stackframes auf dem Stack Kopieren des Parameters Retten von Registern (Kleine Zwischenspeicher in der CPU) Bei jedem Return... Schreiben des Rückgabewertes Wiederherstellen der Register Rekursion ist langsam! fak(1) fak(2) fak(3) fak(4) fak(5) main() Aber: Compiler versuchen Rekursionen in Schleifen zu transformieren. Jedoch ist dies nur bei µ Rekursion möglich! 11.10.2016 Dr. Werner Struckmann / Stephan Mielke, Jakob Garbe Seite 12
Überblick Einleitung Beispiele 11.10.2016 Dr. Werner Struckmann / Stephan Mielke, Jakob Garbe Seite 13
Demo: Einfache Beispiele Live in der Vorlesung Demo: Beispiele zur Rekursion 11.10.2016 Dr. Werner Struckmann / Stephan Mielke, Jakob Garbe Seite 14
Überblick und Ausblick Rekursion Morgen: OOP 11.10.2016 Dr. Werner Struckmann / Stephan Mielke, Jakob Garbe Seite 15
Danke Vielen Dank für Ihre Aufmerksamkeit! 11.10.2016 Dr. Werner Struckmann / Stephan Mielke, Jakob Garbe Seite 16