Rekursive Funktionen (1) Rekursive Algorithmen Wenn Gesamtlösung durch Lösen gleichartiger Teilprobleme erzielbar: Rekursion möglich Beispiel: Fakultät einer ganzen Zahl n: n i n! = i=1 für n > 0 1 für n = 0 Produkt kann auch geschrieben werden als 1 2 3 n 1 n Aufgabe kann auch formuliert werden als: n n 1! für n > 0 n! = 1 für n = 0 Funktion heißt rekursiv, weil die Fakultät von n sich aus n multipliziert mit der Fakultät von n 1 ergibt Abbruchbedingung ist bei n = 0 mit dem Ergebnis 1
Rekursive Funktionen (2) Rekursive Algorithmen Für rekursive Funktionen gelten folgende Regeln Aufgaben werden in gleichartige Teilprobleme zerlegt Jede Rekursion trägt zur Gesamtlösung bei Für mindestens eine Kombination der Funktionsparameter muss die Rekursion beendet werden, was tatsächlich auftreten muss (ein Algorithmus muss terminieren) Bei der Realisierung rekursiver Algorithmen verlässt man sich darauf, dass alle rekursiven Aufrufe funktionieren Teilprobleme werden als gelöst betrachtet (z.b. (n 1)! ) n! = n n 1 gelöst Wichtig: Abbruchbedingung nicht vergessen
Rekursive Funktionen (3) Rekursive Funktionen werden wie normale Funktionen definiert Beispiel einer rekursiven Fakultätsfunktion: long Fakultaet(long n) { if (n == 0) // n ist nur hier sichtbar return 1; // Abbruchbedingung return n * Fakultaet(n - 1); // rekursiver Aufruf } // end Fakultaet Da der Funktionskopf dem Compiler die Funktion bereits bekannt macht, kann diese innerhalb der Funktion nochmals aufgerufen werden Es gelten die üblichen Sichtbarkeitsregeln, z.b. auto: nur innerhalb des Funktionsblocks Wert der Variablen wird im rekursiven Funktionsaufruf übergeben, es wird dann bei der aufgerufenen Funktion eine neue Variable mit dem gleichen Namen angelegt
Rekursive Funktionen () long Fakultaet(long n) { if (n == 0) // n ist nur hier sichtbar return 1; // Abbruchbedingung return n * Fakultaet(n - 1); // rekursiver Aufruf } // end Fakultaet Zunächst wird die Abbruchbedingung für n = 0 codiert Eigentliche Berechnung erfolgt mit n * Fakultaet(n - 1) Lokale Variablen werden auf dem Stack angelegt Bei jedem Aufruf der Funktion werden deshalb neue lokale Variablen oben auf den Stack gelegt und bei beenden der Funktion wieder entfernt Bei erneutem Aufruf der gleichen Funktion passiert das auch Variablen mit gleichem Namen, jedoch anderem Inhalt, da diese jetzt einen ganz anderen Speicherort hat Im Beispiel der Fakultätsfunktion wächst der Stapel, bis Abbruchbedingung erreicht, dann wird alles rückwärts abgearbeitet
Rekursive Funktionen (a) Beispiel eines Parameterstapels bei einer Rekursion mit!
Rekursive Funktionen (b) Beispiel eines Parameterstapels bei einer Rekursion mit!
Rekursive Funktionen (c) Beispiel eines Parameterstapels bei einer Rekursion mit! 3 n bei zweiter Rekursion
Rekursive Funktionen (d) Beispiel eines Parameterstapels bei einer Rekursion mit! 2 3 n bei dritter Rekursion n bei zweiter Rekursion
Rekursive Funktionen (e) Beispiel eines Parameterstapels bei einer Rekursion mit! 1 2 3 n bei vierter Rekursion n bei dritter Rekursion n bei zweiter Rekursion
Rekursive Funktionen (f) Beispiel eines Parameterstapels bei einer Rekursion mit! 0 1 2 3 n bei letzter Rekursion n bei vierter Rekursion n bei dritter Rekursion n bei zweiter Rekursion
Rekursive Funktionen (g) Beispiel eines Parameterstapels bei einer Rekursion mit! 0 1 2 3 n bei letzter Rekursion n bei vierter Rekursion n bei dritter Rekursion n bei zweiter Rekursion Rückgabewert 1 (Abbruchbedingung)
Rekursive Funktionen (h) Beispiel eines Parameterstapels bei einer Rekursion mit! 1 2 3 n bei vierter Rekursion Rückgabewert 1 n bei dritter Rekursion n bei zweiter Rekursion
Rekursive Funktionen (i) Beispiel eines Parameterstapels bei einer Rekursion mit! 2 3 n bei dritter Rekursion Rückgabewert 2 n bei zweiter Rekursion
Rekursive Funktionen (j) Beispiel eines Parameterstapels bei einer Rekursion mit! 3 n bei zweiter Rekursion Rückgabewert 6
Rekursive Funktionen (k) Beispiel eines Parameterstapels bei einer Rekursion mit! Rückgabewert 2
Rekursive Funktionen (l) Beispiel eines Parameterstapels bei einer Rekursion mit! Rückgabewert 120
Rekursive Funktionen (6) Die Variablen werden für jeden Rekursionsschritt neu erzeugt Der Stapel wird in umgekehrter Reihenfolge wieder abgebaut, d. h. die Variablen verschwinden in umgekehrter Reihenfolge wieder vom Stapel Jede Rekursion hat ihren eigenen Variablenset im Stapel trotz namensgleicher Variablen Darunter liegende Variablen sind nicht sichtbar Übergabe von Informationen erfolgt ausschließlich durch Aufrufparameter bzw. durch den Rückgabewert Ein realer Stapel (Programmstack) ist komplizierter: hier werden auch Parameter, Rückgabewerte und Rücksprungadressen gespeichert Das gezeigte Fakultätsbeispiel ist sinnvoller als Schleife zu programmieren (Geschwindigkeit) Rekursionen empfehlenswert, wenn diese einfacher zu beschreiben sind als Schleifen Beispiele: Quicksort, Traversieren von Bäumen Endlosrekursion Stapelüberlauf (stack overflow)