11. Rekursion - fbi.h

Werbung
11. Rekursion
Motivation: Rekursive Definitionen
Rekursive Definitionen sind in der Mathematik verbreitet:
n! =
xn =
n
∑a
i =1
i
=
{
1
falls n=0
n*(n-1)! falls n>0
 n
  =
k 
{
1
x*xn-1
falls n=0
falls n>0
 n
  =
k 
{
0
falls n<=0
n −1
∑ ai + an
i =1
falls n>0
Dr. Norbert Spangler / Programmieren I
{
1
n +1− k  n 

 falls k>0
k
 k − 1
{
1
{
n
Fn-1+Fn-2
Fn =
falls k=0
falls k=0, n=k
 n − 1  n − 1

 + 
 falls n > k>0
k
k
−
1

 

falls n=0,1
falls n>1
01.12.2013
2
Motivation: Rekursive Strukturen
Sequenzielle Struktur
Baumstruktur
Struktur =
Struktur
Struktur = Struktur ->
Dr. Norbert Spangler / Programmieren I
=
Struktur
-> Struktur
01.12.2013
3
Motivation: Rekursive Grafiken
Bilder die sich selbst enthalten
Dr. Norbert Spangler / Programmieren I
01.12.2013
4
Programmierung
Die Programmierung einer rekursiven Funktion in C++ stellt kein Problem dar.
In einer Funktion kann dieselbe Funktion wieder aufgerufen werden
int fakultaet(int n)
{
if ( n==0 )
return 1;
else
return n*fakultaet(n-1);
}
double summe(int n,double a[])
{
if ( n<=0 )
return 0;
else
return summe(n-1,a)+a[n-1];
}
int fibonacci (int n)//rekursiv
{
if ( n==0 )
return 0;
else if ( n==1 )
return 1;
else
return fibonacci(n-1)+fibonacci(n-2);
}
Rekursive Lösungen lassen sich in
der Regel "kürzer/eleganter"
programmieren als iterative
Lösungen mit Schleifen.
int fibonacci(int n)//Schleife
{//iterativ
if ( n==0)
return 0;
else if ( n==1)
return 1;
else
{
int a=0,b=1,c;
for ( int i=2;i<=n;i++)
{
c=b+a; //Addition
a=b;
b=c;
}
}
}
Bzgl. Aufwand bei Fibonacci: Was ist besser? Kriterium : Anzahl der Additionen
Dr. Norbert Spangler /Informatik
01.12.2013
5
Beispiel: Fibonaccizahlen / Aufrufbaum für fibonacci(6)
6
Aufwand Rekursion
Additionen
12
Funktionsaufrufe 25
Fibonacci(0): 5 x
Fibonacci(1): 8 x
Fibonacci(2): 5 x
Fibonacci(3): 3 x
Fibonacci(4): 2 x
Fibonacci(5): 1 x
Fibonacci(6): 1 x
5
4
+
+
2
4
2
Aufwand Schleife
Additionen
5
Funktionsaufrufe 1
+
3
3
+
+
11 + 0 1 + 0
2
1 + 0
Dr. Norbert Spangler / Programmieren I
2
+
3
+
+
11 + 0
2
1 + 0
1
Schleifen verursachen
"weniger" Aufwand (Speicher/Zeit)
01.12.2013
6
Zusammenfassung
Rekursive Programme
sind in der Regel kürzer/einfacher zu formulieren
Iterationen (Schleifen)
sind in der Regel effizienter
(Overhead durch Funktionsaufrufe fehlt)
Häufig lassen sich Rekursionen durch Iterationen ersetzen.
„Faustformel“ für „übliche“ Aufgaben:
Jede Aufgabe lässt sich rekursiv lösen!
Jede Rekursion lässt sich mittels Schleife realisieren!
Gegenbeispiel Ackermannfunktion: keine Lösung mit Schleife
A(0,n)
= n+1
A(m+1,0)
= A(m,1)
A(m+1,n+1)
= A(m,A(m+1,n)
Dr. Norbert Spangler /Informatik
01.12.2013
7
Definition
Rekursion (lat. recurrere) bedeutet Selbstbezüglichkeit
d.h. etwas verweist auf sich selbst.
Interpretation a: Umkehrung der Induktion
Eine Aufgabe lässt sich zerlegen in eine „einfach“ zu lösendes separate Teilaufgabe
und eine weitere Aufgabe, welches vom selben Typ ist wie die Ausgangsaufgabe
mit geringere Komplexität bzw. geringeren Umfang.
Beispiele:
einfach
fakultät(n) =
n
*
Sortiere(n Zahlen) = größtes suchen +
Suche(n Zahlen) = letztes Element testen +
Summe(n Zahlen) = letzte Zahl
+
Dr. Norbert Spangler /Informatik
derselbe Typ/geringerer Umfang
fakultaet(n-1)
Sortiere(n-1 Zahlen)
Suche(n-1 Zahlen)
Summe(n-1 Zahlen)
01.12.2013
8
Definition
Rekursion (lat. recurrere) bedeutet Selbstbezüglichkeit
d.h. etwas verweist auf sich selbst.
Interpretation b: Divide and Conquer (Teile und Herrsche)
Eine Aufgabe lässt sich zerlegen in zwei Teilaufgaben welche vom selben Typ sind
wie die Ausgangsaufgabe aber mit geringere Komplexität bzw. geringeren Umfang.
Die Gesamtlösung wird aus den 2 Teillösungen zusammengesetzt.
Für „ganz“ einfache Fälle ist die Aufgabe direkt lösbar.
Algorithmen
Sortieren
Sortiere (Teil 1)
Sortiere (Teil 2)
Setze die 2 sortierten Teilen zusammen
Einfacher Fall: höchstens 1 Element
Suchen (Binäre Suche)
Test für linke Hälfte->Suche(linke Hälfte)
Test für rechte Hälfte-> Suche(rechte Hälfte)
gefunden
Einfacher Fall: kein Element
Dr. Norbert Spangler /Informatik
01.12.2013
9
Beispiel: Suche
Prinzip: Umkehrung Induktion
Man testet ob es das letzte Element ist und sucht, falls nicht
gefunden, im Rest mit derselben Technik.
Ist kein Element mehr da zum Vergleich, dann wird nichts
gefunden.
int suche (int n, int a[],int element)
{
if ( n==0 )
return -1;//nicht gefunden
else if ( a[n-1] ==element )
return n-1;//gefunden
else
return suche(n-1,a,element);// im Rest weitersuchen
}
Dr. Norbert Spangler /Informatik
01.12.2013
10
Sortieren (Quicksort klassisch)
Prinzip: Teile und Herrsche
Dr. Norbert Spangler / Programmieren I
01.12.2013
11
Türme von Hanoi
Start
Hilfe
Ziel
n Scheiben
Alle Scheiben müssen von
Start nach Ziel unter
Verwendung von Hilfe
umgelegt werden, wobei
immer nur eine Scheibe
bewegt werden und eine
größere Scheibe nie auf eine
kleinere gelegt werden darf.
Tuerme(int anzahl,char start,char hilfe,char ziel)
{
if ( anzahl>0 )
{
Tuerme(anzahl-1,start,ziel,hilfe);
cout<<"von "<<start<<" nach "<<ziel<<endl;
Tuerme(anzahl-1,hilfe,start,ziel);
}
}
Dr. Norbert Spangler /Informatik
01.12.2013
12
Pythagoräischer Baum
Baum(Seite)
falls Seite zu kurz -> Ende
errichte über der Seite ein Quadrat
zeichne über der gegenüberliegenden Seite ein Dreieck mit vorgegebenen Winkeln
Baum(neue Dreieckseite1)
Baum(neue Dreieckseite2)
Dr. Norbert Spangler /Informatik
01.12.2013
13
Weitere rekursive Ansätze
Listenverarbeitung(Arrays)
Bearbeite(Liste) = Bearbeite(letztes Element) + Bearbeite(Rest) oder
Bearbeite(erstes Element) + Bearbeite(Rest)
Summation
Summe(Array) = letztes Element+Summe(Rest)
Potenzreihen
neuer Summand=letzter Summand * Faktor
n
j
∑ a j x : Berechne
j =0
(− x 2 ) j
( − x 2 ) j +1
:
∑
2( j + 1)!
j =0 2 j!
n
Faktor =
=
Dr. Norbert Spangler / Programmieren I
a j +1 x j +1
ajx
(− x 2 ) j
2 j!
j
=
a j +1
aj
x
(− x 2)
*
( 2 j + 1)( 2 j + 2)
01.12.2013
14
Generelle Vorgehensweise
Allgemeine Fragestellungen bei einer gegebenen Aufgabe:
Ist die Aufgabe rekursiv und/oder iterativ lösbar?
Was ist das Schema der Rekursion?
Lässt sich die Aufgabe in "2 Hälften zerlegen" und dann zusammensetzen?
Lässt sich die Aufgabe um ein Objekt reduzieren und dann zusammensetzen?
Was ist wichtig:
Einfachkeit des Programms (Lesbarkeit)
Termin der Fertigstellung
Effizienz
Die Programmierung rekursiv definierter Funktionen stellt kein Problem dar, da
man sie in der Regel direkt programmieren kann.
Allerdings sind iterative Lösungen nicht immer direkt erkennbar bzw. teilweise
auch unmöglich (Ackermann, Türme von Hanoi).
Dr. Norbert Spangler / Programmieren I
01.12.2013
15
Herunterladen