Programmierkurs Java Teil Imperative Programmierung Unterrichtseinheit 16 Rekursion

  • Slides: 31
Download presentation
Programmierkurs Java Teil Imperative Programmierung Unterrichtseinheit 16 Rekursion Dr. Dietrich Boles Programmierkurs Java UE

Programmierkurs Java Teil Imperative Programmierung Unterrichtseinheit 16 Rekursion Dr. Dietrich Boles Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 1

Gliederung Ø Rekursion Ø Definitionen Ø Rekursive Prozeduren Ø Rekursive Funktionen Ø Lokale Variablen

Gliederung Ø Rekursion Ø Definitionen Ø Rekursive Prozeduren Ø Rekursive Funktionen Ø Lokale Variablen Ø Parameter Ø Endlosrekursion Ø Anmerkungen Ø Beispiele Ø Backtracking Ø Zusammenfassung Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 2

Rekursion (1) Ø "Definition eines Problems, einer Funktion oder eines Verfahrens durch sich selbst"

Rekursion (1) Ø "Definition eines Problems, einer Funktion oder eines Verfahrens durch sich selbst" Ø bereits bekannt: Ø direkt rekursive Syntaxdiagramme/EBNF: <boolescher Ausdruck> : : "true" | "false" | "(" <boolscher Ausdruck> ")" ; Ø indirekt rekursive Syntaxdiagramme/EBNF: <Anweisung> : : =. . . | <while-Anweisung> ; <while-Anweisung> : : = "while" "(" <b. A> ")" <Anweisung> ; Ø Mathematik: n! = { 1 falls n = 0 n * (n-1)! sonst Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 3

Rekursion (2) Ø Spielzeug: Quelle: German Wikipedia Matroschka Programmierkurs Java UE 16 Rekursion Dietrich

Rekursion (2) Ø Spielzeug: Quelle: German Wikipedia Matroschka Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 4

Rekursion (3) Ø Kunst: M. C. Escher; Bildgalerie Programmierkurs Java UE 16 Rekursion Dietrich

Rekursion (3) Ø Kunst: M. C. Escher; Bildgalerie Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 5

Rekursion (4) Ø Fraktale: Pythagoras-Baum Quelle: German Wikipedia Programmierkurs Java UE 16 Rekursion Dietrich

Rekursion (4) Ø Fraktale: Pythagoras-Baum Quelle: German Wikipedia Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 6

Rekursion (5) Ø Fraktale: Quelle: German Wikipedia, Wolfgag Beyer Mandelbrotmenge http: //www. mathematik. ch/anwendungenmath/fractal/julia/Mandelbrot.

Rekursion (5) Ø Fraktale: Quelle: German Wikipedia, Wolfgag Beyer Mandelbrotmenge http: //www. mathematik. ch/anwendungenmath/fractal/julia/Mandelbrot. Applet. php Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 7

Definitionen (1) Definition (Rekursion): Eine Funktion heißt rekursiv, wenn sie während ihrer Abarbeitung erneut

Definitionen (1) Definition (Rekursion): Eine Funktion heißt rekursiv, wenn sie während ihrer Abarbeitung erneut aufgerufen wird. Definition (direkte Rekursion): Eine Funktion heißt direkt rekursiv, wenn der erneute Aufruf im Funktionsrumpf der Funktion erfolgt. Definition (indirekte Rekursion): Eine Funktion heißt indirekt rekursiv, wenn der erneute Aufruf nicht im Funktionsrumpf der Funktion selbst sondern in einer anderen Funktion erfolgt. Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 8

Definitionen (2) Definition (Funktionsinkarnation): konkreter Aufruf einer Funktion Definition (Rekursionstiefe): Anzahl der aktuellen Inkarnationen

Definitionen (2) Definition (Funktionsinkarnation): konkreter Aufruf einer Funktion Definition (Rekursionstiefe): Anzahl der aktuellen Inkarnationen einer Funktion minus 1 Definition (Variableninkarnation): konkrete Ausprägung (Speicherplatz) einer Variablen Iterativer Algorithmus: Algorithmus, der Wiederholungsanweisungen verwendet Rekursiver Algorithmus: Algorithmus, der rekursive Funktionen verwendet Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 9

Rekursive Prozeduren (1) Der Hamster soll bis zur nächsten Wand laufen! Iterative Lösung: void

Rekursive Prozeduren (1) Der Hamster soll bis zur nächsten Wand laufen! Iterative Lösung: void zur. Mauer() { while (vorn. Frei()) vor(); } Direkt rekursive Lösung: void zur. Mauer. R() { if (vorn. Frei()) { vor(); zur. Mauer. R(); } } Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 10

Rekursive Prozeduren (2) Der Hamster soll alle Körner auf dem aktuellen Feld einsammeln! Iterative

Rekursive Prozeduren (2) Der Hamster soll alle Körner auf dem aktuellen Feld einsammeln! Iterative Lösung: void sammle() { while (korn. Da()) nimm(); } Direkt rekursive Lösung: void sammle. R() { if (korn. Da()) { nimm(); sammle. R(); } } Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 11

Rekursive Prozeduren (3) Der Hamster soll bis zur nächsten Wand und dann zurück zur

Rekursive Prozeduren (3) Der Hamster soll bis zur nächsten Wand und dann zurück zur Ausgangsposition laufen! Iterative Lösung: void hin. Und. Zurueck() { int anzahl = 0; while (vorn. Frei()) { vor(); anzahl++; } links. Um(); while (anzahl > 0) { vor(); anzahl--; } } Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 12

Rekursive Prozeduren (4) Der Hamster soll bis zur nächsten Wand und dann zurück zur

Rekursive Prozeduren (4) Der Hamster soll bis zur nächsten Wand und dann zurück zur Ausgangsposition laufen! Direkt rekursive Lösung: void hin. Und. Zurueck. R() { if (vorn. Frei()) { vor(); hin. Und. Zurueck. R(); vor(); } else { kehrt(); } } void kehrt() { links. Um(); } Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 13

Rekursive Prozeduren (5) Schema: main: h. UZR (1. ) h. UZR(); h. UZR (2.

Rekursive Prozeduren (5) Schema: main: h. UZR (1. ) h. UZR(); h. UZR (2. ) h. UZR (3. ) vorn. Frei -> t vor(); h. UZR(); -----> vorn. Frei -> f kehrt(); <----vor(); <----Befehlsfolge: vor(); kehrt(); vor(); Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 14

Rekursive Prozeduren (6) Der Hamster soll bis zur nächsten Wand und dann zurück zur

Rekursive Prozeduren (6) Der Hamster soll bis zur nächsten Wand und dann zurück zur Ausgangsposition laufen! Indirekt rekursive Lösung: void hin. Und. Zurueck. R() { if (vorn. Frei()) { laufe(); } else { links. Um(); } } void laufe() { vor(); hin. Und. Zurueck. R(); vor(); } Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 15

Rekursive Funktionen (1) Der Hamster soll die Anzahl an Schritten bis zur nächsten Mauer

Rekursive Funktionen (1) Der Hamster soll die Anzahl an Schritten bis zur nächsten Mauer zählen! Iterative Lösung: int anzahl. Schritte() { int anzahl = 0; while (vorn. Frei()) { vor(); anzahl++; } return anzahl; } Rekursive Lösung: int anzahl. Schritte. R() { if (vorn. Frei()) { vor(); return anzahl. Schritte. R() + 1; } else return 0; } Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 16

Rekursive Funktionen (2) Schema: main: a. SR (1. ) a. SR (2. ) a.

Rekursive Funktionen (2) Schema: main: a. SR (1. ) a. SR (2. ) a. SR (3. ) i=a. SR(); vorn. Frei -> t vor(); a. SR() -----> vorn. Frei -> f return 0; 0 <----return 0 + 1; 1 <----return 1 + 1; 2 <----i=2; Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 17

Lokale Variablen Der Hamster soll die Anzahl an Körnern im Maul zählen! Speicher int

Lokale Variablen Der Hamster soll die Anzahl an Körnern im Maul zählen! Speicher int anzahl. Koerner. R() { if (!maul. Leer()) { int anz = 0; gib(); anz = anzahl. Koerner. R(); nimm(); // Vermeidung von Seiteneffekten! return anz + 1; } else return 0; } a. KR main anz a. KR anz main Programmierkurs Java . . . main UE 16 Rekursion Dietrich Boles Seite 18

Parameter Der Hamster soll "anz"-Schritte nach vorne gehen! void vor. R(int anz) { if

Parameter Der Hamster soll "anz"-Schritte nach vorne gehen! void vor. R(int anz) { if ((anz > 0) && vorn. Frei()) { vor(); vor. R(anz-1); } } Speicher vor. R main anz=2 vor. R anz=0 vor. R anz=1 vor. R anz=2 main Programmierkurs Java . . . main UE 16 Rekursion Dietrich Boles Seite 19

Endlosrekursion: void sammle. R() { if (korn. Da()) { sammle. R(); nimm(); } }

Endlosrekursion: void sammle. R() { if (korn. Da()) { sammle. R(); nimm(); } } Rekursionstiefe: im Prinzip "unendlich"! erzeugt im allgemeinen Laufzeitfehler: Stack overflow! Dem Java-Interpreter kann man die gewünschte Stackgröße mitteilen! Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 20

Anmerkungen Ø Satz: Ø zu jedem rekursiv formulierten Algorithmus gibt es einen äquivalenten iterativen

Anmerkungen Ø Satz: Ø zu jedem rekursiv formulierten Algorithmus gibt es einen äquivalenten iterativen Algorithmus Ø Vorteile rekursiver Algorithmen: Ø Ø kürzere Formulierung leichter verständliche Lösung Einsparung von Variablen teilweise sehr effiziente Problemlösungen (z. B. Quicksort) Ø Nachteile rekursiver Algorithmen: Ø weniger effizientes Laufzeitverhalten (Overhead beim Funktionsaufruf) Ø Verständnisprobleme bei Programmieranfängern Ø Konstruktion rekursiver Algorithmen "gewöhnungsbedürftig" Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 21

Beispiel 1 Anzahl an Ziffern einer Zahl ermitteln: static int length(int zahl) { if

Beispiel 1 Anzahl an Ziffern einer Zahl ermitteln: static int length(int zahl) { if (zahl == 0) return 1; int laenge = 0; while (zahl != 0) { zahl /= 10; laenge++; } return laenge; } // iterativ static int length. R(int zahl) { // rekursiv if (zahl >= -9 && zahl <= 9) return 1; return length. R(zahl/10) + 1; } Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 22

Beispiel 2 Berechnung der Fakultätsfunktion: n! = { 1 falls n = 0 n

Beispiel 2 Berechnung der Fakultätsfunktion: n! = { 1 falls n = 0 n * (n-1)! sonst static int fak(int n) { if (n <= 0) return 1; else return n * fak(n-1); } fak(3) = 3 * fak(2) 2 * fak(1) 1 * fak(0) 1 1 * 1 2 * 1 3 * 2 6 Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 23

Beispiel 3 Berechnung einer Fibonacci-Zahl: { fib(n) = 1 falls n = 1 1

Beispiel 3 Berechnung einer Fibonacci-Zahl: { fib(n) = 1 falls n = 1 1 falls n = 2 fib(n-1) + fib(n-2) sonst static int if (n <= return else return } fib(int n) { 2) 1; fib(n-1) + fib(n-2); Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 24

Beispiel 4 Türme von Hanoi: Gegeben: 3 Pfosten mit n Scheiben Ziel: Lege alle

Beispiel 4 Türme von Hanoi: Gegeben: 3 Pfosten mit n Scheiben Ziel: Lege alle n Scheiben von 1 nach 3 Restriktion 1: immer nur eine Scheibe bewegen Restriktion 2: niemals größere auf kleinere Scheibe 1 2 3 http: //thinks. com/java/hanoi. htm class Hanoi { public static void main(String[] args) { int hoehe = IO. read. Int("Hoehe: "); verlege. Turm(hoehe, 1, 3, 2); } static void verlege. Turm(int hoehe, int von, int nach, int ueber) { if (hoehe > 0) { verlege. Turm(hoehe-1, von, ueber, nach); IO. println(von + "-" + nach); verlege. Turm(hoehe-1, ueber, nach, von); Demo } } } Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 25

Backtracking-Verfahren (1) Ø Prinzip: Ø Versuch, eine Teillösung eines gegebenen Problems systematisch zu einer

Backtracking-Verfahren (1) Ø Prinzip: Ø Versuch, eine Teillösung eines gegebenen Problems systematisch zu einer Gesamtlösung auszubauen Ø falls in einer gewissen Situation ein weiterer Ausbau einer vorliegenden Teillösung nicht mehr möglich ist ("Sackgasse"), werden eine oder mehrere der letzten Teilschritte rückgängig gemacht Ø die dann erhaltene reduzierte Teillösung versucht man auf einem anderen Weg wieder auszubauen Ø Wiederholung des Verfahrens, bis Lösung gefunden wird oder man erkennt, dass keine Lösung existiert Ø Grundlage der Programmiersprache PROLOG! Ø Bekannte Probleme: Ø Springerproblem Ø Acht-Damenproblem Ø Labyrinthsuche Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 26

Backtracking-Verfahren (2) Aufgabe: Der Hamster steht am Eingang eines zyklenfreien Labyrinths, in dem er

Backtracking-Verfahren (2) Aufgabe: Der Hamster steht am Eingang eines zyklenfreien Labyrinths, in dem er ein Korn finden und auf dem schnellsten Weg zurücktransportieren soll! Demo Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 27

Backtracking-Verfahren (3) void main() { durchsuche. Labyrinth(); } boolean durchsuche. Labyrinth() { if (korn.

Backtracking-Verfahren (3) void main() { durchsuche. Labyrinth(); } boolean durchsuche. Labyrinth() { if (korn. Da()) { nimm(); kehrt(); // mach dich auf den Heimweg return true; } if (links. Frei() && durchsuche. Teil. Labyrinth. Links()) { kehrt(); // mach dich auf den Heimweg return true; } if (rechts. Frei() && durchsuche. Teil. Labyrinth. Rechts()) { kehrt(); // mach dich auf den Heimweg return true; } Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 28

Backtracking-Verfahren (4) if (!vorn. Frei()) { kehrt(); // Sackgasse return false; } return durchsuche.

Backtracking-Verfahren (4) if (!vorn. Frei()) { kehrt(); // Sackgasse return false; } return durchsuche. Teil. Labyrinth. Vorne(); } boolean durchsuche. Teil. Labyrinth. Links() { links. Um(); vor(); boolean gefunden = durchsuche. Labyrinth(); // Ausgangsposition einnehmen vor(); links. Um(); return gefunden; } Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 29

Backtracking-Verfahren (5) boolean durchsuche. Teil. Labyrinth. Rechts() { rechts. Um(); vor(); boolean gefunden =

Backtracking-Verfahren (5) boolean durchsuche. Teil. Labyrinth. Rechts() { rechts. Um(); vor(); boolean gefunden = durchsuche. Labyrinth(); // Ausgangsposition einnehmen vor(); rechts. Um(); return gefunden; } boolean durchsuche. Teil. Labyrinth. Vorne() { vor(); boolean gefunden = durchsuche. Labyrinth(); vor(); // Seiteneffekt: Hamster schaut in andere Richtung return gefunden; } // + Hilfsfunktionen Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 30

Zusammenfassung Ø Rekursive Funktionen: Funktionen, die während ihrer Abarbeitung erneut aufgerufen werden Ø Backtracking-Verfahren:

Zusammenfassung Ø Rekursive Funktionen: Funktionen, die während ihrer Abarbeitung erneut aufgerufen werden Ø Backtracking-Verfahren: Problemlösungsverfahren, das rekursiv Teilwege durchforstet, um eine Lösung zu finden Programmierkurs Java UE 16 Rekursion Dietrich Boles Seite 31