17-1_Rekursion

Werbung
REKURSION +
ITERATION
Manchmal ist es sinnvoll
auf schon Erschafftes
zurückzugreifen, wie z.B.
auf das im Lauf der Zeit
durch Generationen vor uns
angehäufte
Menschheitswissen
Aus dem alten
Menschheitswissen einer
Generation aufbauend wird
das neue
Menschheitswissen erzeugt.
Das geschah immer wieder
bis zur heutigen Generation.
Mathematisch könnte man
dies wie folgt modellieren:
Es beginnt mit dem
"Urknall" (= leere Menge).
Daraus wird dann (nach
einer bestimmten Regel)
eine neue Menge
konstruiert (produziert):
Die Menge der Atome.
Aus dieser wird dann
wieder (nach einer
bestimmten Regel) eine
neue Menge konstruiert
(produziert):
Die Menge der Moleküle,
usw.
Die Vereinigung all dieser
Mengen ergibt dann die
Gesamtmenge. Man sagt:
Diese Gesamtmenge wurde
induktiv definiert (induktive
Definition)
Mit der leeren Menge
beginnt alles
Aus dieser wird dann (mit
Hilfe einer Regel) eine neue
gebastelt.

…
Aus dieser wird dann
wieder (mit Hilfe einer
Regel) eine neue gebastelt,
usw.
Die Vereinigung all dieser
Mengen ist die zu
konstruierende Gesamtmenge.
Dieses Verfahren nennt man
Iteration (iterativ)
(lateinisch iterare =
wiederholen)
Beispiel:
Zu dem Ausrufezeichen sagt man
Fakultät
Definition:
n! = n * (n-1) * (n-2) * ... * 1
Was ist dann 5 Fakultät?
5! = 5 * 4 * 3 * 2 * 1 =120
Die Fakultät kann man mit
Hilfe von Regeln
berechnen.

----(1,1)
Regel R1:
Die leere Menge produziert die Fakultät von 1
(links die Zahl, rechts in rot die Fakultät davon)
Regel R2:
Aus der Fakutät von n wird die Fakultät
von n+1 produziert
(n,fak)
------------------(n+1,fak*(n+1))
Mit der leeren Menge
beginnt alles

(1,1)
(2,1*2)
(3,2*3)
…
Aus dieser wird dann (mit
Hilfe von R1) eine neue
gebastelt.
Aus dieser wird dann (mit
Hilfe von R2) wieder eine
neue gebastelt.
Aus dieser wird dann (mit
Hilfe von R2) wieder eine
neue gebastelt, usw.
Die Vereinigung all dieser
Mengen ist die zu konstruierende
Gesamtmenge.
Aufgabe:
Erstellen Sie die Funktion
fak (Parameter, Rückgabe
bitte selbst überlegen), die
die Fakultät einer Zahl
berechnet.
Aus dem alten Produkt
wird das …
int fak(int zahl){
int i;
int produkt=1;
for(i=1;i<=zahl;i++){
produkt = produkt*i;
}
…neue Produkt
return produkt;
}
Weitere
Lösung:
Angenommen, jemand hätte
schon fak(n-1) berechnet.
Wie kann man mit Hilfe
von fak(n-1) den Wert von
fak(n) berechnen?
fak(n) = fak(n-1) * n
Rekursion: fak kommt links und rechts
des Gleichheitszeichens vor!
Aufgabe:
Erstellen Sie die Funktion
fakRek (int zahl), die die
Fakultät einer Zahl
berechnet und im
Funktionskörper den in der
letzten Folie erarbeiteten
Zusammenhang verwendet.
int fakRek(int zahl){
int prod;
prod=fakRek(zahl-1)*zahl;
return prod;
}
Dieses Verfahren nennt man
Rekursion (lat. recurrere =
zurücklaufen)
Konkret:
Was passiert beim Aufruf
von
fakRek(3)
fakRek(3)
zahl=3
(Kopie)
}
int prod;
3
3
prod=fakRek(zahl-1)*zahl;
return prod;
2
Bevor die Anweisung
return prod;
gemacht werden kann, muss zuerst
fakRek(2) abgearbeitet werden!
Zusammengefasst:
fakRek(3)
prod=fakRek(2)*3;
return prod;
Das Programm ist in
einer
Endlosschleife!
prod=fakRek(1)*2;
return prod;
prod=fakRek(0)*1;
return prod;
prod=fakRek(-1)*0;
return prod;
...
Wie muss also unser
Programm noch abgeändert
werden, damit es
funktioniert?
int fakRek(int zahl){
int prod;
if(zahl==1){
prod=1;
}
else{
prod=fakRek(zahl-1)*zahl;
}
return prod;
}
Konkret:
Was passiert beim Aufruf
von
fakRek(3)
6
fakRek(3)
2
prod=fakRek(2)*3;
return prod; 6
1
prod=fakRek(1)*2;
return prod; 2
prod=1;
return prod; 1
Vorbereitung für eine Aufgabe:
Ein Biologe hat die Entwicklung einer
Hasenpopulation beobachtet.
1. Generation: 2 Hasen.
2. Generation: 4 Hasen.
3. Generation: 2+4 = 6 Hasen.
4. Generation: 4+6 = 10 Hasen.
5. Generation: 6+10=16 Hasen.
...
Wie geht es allgemein weiter ?
Wie berechnet man die Anzahl der Hasen?
Die Anzahl der Hasen berechnet sich also
(ab der 3. Generation) aus der Summe der
Anzahl der Hasen der letzten 2
Generationen. Die Anzahl der 1. und 2.
Generation ist fest vorgeben und hat z.B.
die Werte:
Anzahl Hasen der 1. Generation : 2
Anzahl Hasen der 2. Generation : 4
Diese Folge von Zahlen nennt man die
sogenannte
Fibonacci-Folge .
Die Fibonacci-Folge ist eine unendliche
Folge von Zahlen (den Fibonacci-Zahlen),
bei der sich die jeweils folgende Zahl
durch Addition ihrer beiden vorherigen
Zahlen ergibt.
Benannt ist sie nach Leonardo Fibonacci,
der damit 1202 das Wachstum einer
Kaninchenpopulation beschrieb.
An Hand dieser FibonacciFolge als Beispiel kann man
das allgemeine Prinzip und die
Struktur einer Rekursion
darstellen: den Baum.
Ein Baum bildet die Struktur
einer Rekursion !!
Also nochmals (ganz wichtig):
Ein Baum bildet
die
Struktur einer
Rekursion !!
Ausgangspunkt ist das
folgende Zweier-Paket
(Zweier-Tupel):
(n,w)
w = N(n)
(n,w)
wobei n die n-te Generation und w
die noch unbekannte, zu
berechnende Populationsgröße
bedeutet. Das 2. Element im Tupel
ist der Nachbar des 1. Elements,
also der Nachbar von n. Er wird
hier deshalb mit N (wie Nachbar)
bezeichnet.
die n-te Generation deren Population berechnet werden soll
( n,N(n))
Dazu errechnet man die 2 vorhergehenden
Generationen d.h. bildet die 2 Nachfolger im Baum
gilt für n ≥ 3
(n-1,N(n-1)) (n-2,N(n-2))
... und tut dann so, als ob Populationsgrößen w1=N(n-1), und
w2=N(n-2) der Nachfolger n-1 und n-2 bekannt wären.
Wie kann man dann die Populationsgrößen w = N(n) durch die
Populationsgrößen N(n-1) und N(n-2) berechnen?
N(n) = N(n-1) + N(n-2) für n ≥ 3
Rekursion: N kommt links und rechts des
Gleichheitszeichens vor!
Aufgabe:
1) Implementieren Sie die Funktion
fibIt(...) iterativ.
2) Implementieren Sie die Funktion
fibRek(...) rekursiv.
#include "stdafx.h"
int fibIt(int n);
Fibonacci mit Iteration
Anzahl Hasen der n-ten
Generation
int main(){
int erg;
int n;
n=5;
erg = fibIt(n);
printf("fibIt(%d)=%d\n",
n,erg);
return 0;
}
int fibIt(int n){
int i;
int anzahl;
int anzahl_1;
int anzahl_2;
if(n==1){
anzahl=2;
}
else if(n==2){
anzahl=4;
}
Anzahl der Hasen der
aktuellen Generation.
Anzahl der Hasen der letzten
Generation.
Anzahl der Hasen der
vorletzten Generation.
anzahl bestimmen
else{
anzahl_1 = 4;
neue anzahl_2 bestimmen
anzahl_2 = 2; neue anzahl_1 bestimmen
for(i=3;i<=n;i++){
anzahl=anzahl_1+anzahl_2;
anzahl_2 = anzahl_1;
anzahl_1 = anzahl;
}
}
return anzahl;
}
#include "stdafx.h"
int fibRek(int n);
Fibonacci mit
Rekursion
Anzahl Hasen der n-ten
Generation
int main(){
int erg;
int n;
n=5;
erg = fibRek(n);
printf("fibRek(%d)=%d\n",
n,erg);
return 0;
}
int fibRek(int n){
Um Codezeilen zu sparen,
int anzahl;
wurden überall bei if und else
if(n==1)
die Klammern { und }
eingespart. Warum geht das ?
anzahl=2;
else if(n==2) Weil sich im jeweiligen if bzw.
anzahl=4;
else Teil nur genau eine
Anweisung befindet.
else
anzahl=fibRek(n-1)+
fibRek(n-2);
return anzahl;
}
Herunterladen