Einführung in die Informatik I

Werbung
Einführung in die
Informatik I
Fortgeschrittene Rekursion
Prof. Dr. Nikolaus Wulff
Problematische Rekursion
• Mittels Rekursion lassen sich Spezifikationen recht
elegant und einfach implementieren.
• Leider sind jedoch die so erhaltenen Lösungen meist
nicht sehr effizient, was den Speicherverbrauch und
die Laufzeit betrifft.
• Da sich jede primitive Rekursion durch eine iterative
Lösung mittels Schleifen darstellen lässt, gilt es einen
strukturierten Weg zu finden, um eine rekursive
Lösung in eine Iterative zu überführen.
• Ein erster Schritt hierzu die Endrekursion, die eine
effizientere Implementierung gestattet.
Prof. Dr. Nikolaus Wulff
Informatik I
2
Endrekursion
• Eine Rekursion heißt endrekursiv, wenn der Aufruf
der Rekursion die letzte Aktion zur Berechnung der
rekursiven Funktion f ist.
• Endrekursive Funktionen zeigen ein besseres Verhalten hinsichtlich des Speicherbedarfs für lokale
Variablen und den Stack, als normal rekursive Funktionen, die nach der Rekursion noch weitere Berechnungen vornehmen.
• Am Beispiel der rekursiven Fakultätsberechnung soll
das Prinzip verdeutlicht werden.
Prof. Dr. Nikolaus Wulff
Informatik I
3
Rekursive Fakultät
int factorial(int n) {
if(n<=1) return 1;
return n*factorial(n-1);
}
• Diese Implementierung der Fakultät ist nicht
endrekursiv, da nach der Rekursion noch eine
Multiplikation mit dem Argument n erfolgt.
• Sie ergibt sich z.B. für n=4 die Aufruffolge 4!:
f(4) = 4·f(3)
=> f(4)=4·6=24
f(3)= 3·f(2)
=> f(3)=3·2=6
f(2) = 2·f(1) => f(2)=2·1=2
LIFO
f(1)=1
Berechnung
Prof. Dr. Nikolaus Wulff
Informatik I
4
Endrekursion mittels Hilfsfunktion
int g_factorial(int n, int fac) {
if (n<=1) return fac;
return g_factorial(n-1, fac*n);
}
int factorial(int n) {
return g_factorial(n, 1);
}
• Durch Einführen der Hilfsfunktion g_factorial wird
die nachträgliche Multiplikation vermeiden.
• Die Rekursion ist nun endrekursiv.
f(4) = g(4,1) = g(3,1·4)
g(3,4) = g(2,4·3)
g(2,12) = g(1,12·2) = 24
Prof. Dr. Nikolaus Wulff
Informatik I
5
Nichtlineare Rekursion
• Bei der Endrekursion entfallen viele der Zwischenergebnisse, die auf dem Stack vorgehalten werden und
die Funktion kann am Ende der Rekursion direkt
terminieren.
• An dem einfachen Beispiel der Fakuktät kommt
dieser Vorteil noch nicht so deutlich zum Tragen, da
hier die Rekursion linear verläuft, anders wird dies bei
nichtlinearen Rekursionen.
• Eine nichtlineare Rekursion liegt vor, wenn im
Rumpf der Definition von f mehr als ein rekursiver
Aufruf ist.
Prof. Dr. Nikolaus Wulff
Informatik I
6
Nichtlineare Rekursion
• Ein besonders schlechtes Lauftzeitverhalten hat die
nichtlineare Rekursion, wie sie z.B. bei den Fibonacci
Zahlen: 1, 1, 2, 3, 5, 8, 13, 21, 34, ... vorkommt.
f n := f n−1  f n−2
f 1 := f 2 :=1
• Die Aufruffolge zeigt, dass viele Fibonacci Zahlen
mehrfach berechnet werden und ~2n Auswertungen
fn
notwendig sind:
fn-1
fn-2
fn-3
Prof. Dr. Nikolaus Wulff
fn-2
fn-3
fn-3
fn-4
...
fn-4
Informatik I
7
Auflösen der Rekursion
• Es ist offensichtlich, dass diese rekursive Lösung
nicht effizient ist und viele der Zahlen fk unnötig oft
berechnet werden.
• Zum Berechnen von fk werden lediglich die direkten
Vorgängerzahlen fk-1 und fk-2 benötigt. Wenn der
Algorithmus diese bei der Berechnung nur einmal
berechnet und ab dann wiederverwendet, so wird sich
die Rekursion wesentlich verkürzen.
• Hierzu wird eine Hilfsfunktion g eingeführt, welche
die Fibonacci-Zahl fk aus den beiden vorhergehenden
Funktionswerten mit linearer Endrekursion berechnet.
Prof. Dr. Nikolaus Wulff
Informatik I
8
Linearisierung der Rekursion
int g_fibonacci(int n, int fk1, int fk2) {
if (n<=1) return fk1+fk2;
return g_fibonacci(n-1, fk2+fk1, fk1);
}
int fibonacci(int n) {
return g_fibonacci(n-1,1,0);
}
• Aus der nichtlinearen Rekursion ist mittels der
Hilfsfunktion g eine Endrekursion geworden.
• Diese Lösung hat eine lineare Laufzeit ~n im
Vergleich zur ursprünglichen rekursiven Lösung ~2n
Prof. Dr. Nikolaus Wulff
Informatik I
9
Endrekursion > Iterative Lösung
• Ist erst einmal eine endrekursive Lösung gefunden
worden, so ist es meistens leicht, daraus eine iterative
Lösung zu entwickeln, die hinsichtlich der Laufzeit
immer die bessere Variante darstellt.
• Die generische Struktur einer linearen Rekursion ist:
{
g n
falls T n
f n=
h n , f n−1
sonst
• Hierbei ist T(n) die terminierende Bedingung und im
Spezialfall h(n,y)=y=f(n) ergibt sich die
Endrekursion, die sich durch ein LOOP Programm,
d.h eine einfache n-fache for-Schleife berechnen lässt.
Prof. Dr. Nikolaus Wulff
Informatik I
10
Iterative Lösung
unsigned fibonacci(unsigned n) {
unsigned f, fk1=1, fk2=0;
while (--n) {
f
= fk1 + fk2;
fk2 = fk1, fk1 = f;
}
return fk1;
}
• Diese iterative Lösung hat die Hilfsfunktion g durch
eine Schleife ersetzt und besitzt sowohl eine optimale
Laufzeit als auch den minimalen Speicherverbrauch.
Prof. Dr. Nikolaus Wulff
Informatik I
11
Wechselseitige Rekursion
unsigned even(unsigned n) {
if (n==0) return 1;
return odd(n-1);
}
unsigned odd(unsigned n) {
if(n==0) return 0;
return even(n-1);
}
• Indirekte Rekursion liegt vor, wenn eine Funktion f
eine Funktion h aufruft, die direkt oder indirekt
wiederum eine Rekursion der Funktion f aufruft, wie
hier am Beispiel der Funktionen even und odd, die
berechnen ob eine Zahl n gerade oder ungerade ist.
Prof. Dr. Nikolaus Wulff
Informatik I
12
Weitere Rekursionen
• Das letzte Beispiel ist ziemlich künstlich, ob eine Zahl
n gerade oder ungerade ist, lässt sich mit der Modulo
Operation n%2 == 1 viel einfacher und schneller
herausbekommen.
• Das Bisektionsverfahren zur Nullstellensuche oder
dem Zahlenraten lässt sich rekursiv durchführen.
• Rekursion wird nicht nur für rein mathematische Aufgaben verwendet, sondern auch bei Strategiespielen,
die sich im weitesten Sinne auf Rekursion zurückführen lassen:
– Wolf, Schaf und Kohl mit Floss
– Das acht Damen Problem
Prof. Dr. Nikolaus Wulff
Informatik I
13
Graphische Rekursionen
• Mittels Rekursion lassen sich graphische Algorithmen
entwickeln wie z.B. die fraktale Koch Kurve (1904).
• Eine Strecke wird in drei gleichlange Teile zerlegt.
Das mittlere Teilstück wird verdoppelt und die
beiden werden mit einem 60° Winkel eingefügt.
Anschließend wird diese Vorschrift rekursiv auf alle
Teilstücke angewandt.
1. Rekursion
0. Rekursion
Prof. Dr. Nikolaus Wulff
Informatik I
14
Entwicklung der Koch Kurve
Rekursionstiefe:
1
2
3
4
5
Prof. Dr. Nikolaus Wulff
Informatik I
15
Hilbert Kurve
• Die Kurve entsteht durch vier Zeichenfunktionen, die
sich wechselseitig rekursiv aufrufen...
Prof. Dr. Nikolaus Wulff
Informatik I
16
Entwicklung der Hilbert Kurve
1
4
2
3
5
6
• Mit zunehmender Rekursionstiefe wird die Kurve
immer filigraner und berührt im Limes jeden Punkt
der Fläche und füllt diese vollständig aus...
Prof. Dr. Nikolaus Wulff
Informatik I
17
Herunterladen