Rekursion

Werbung
Babeș-Bolyai Universität
Cluj Napoca
Fakultät für Mathematik und Informatik
Grundlagen der Programmierung MLG5005
Rekursion
Rekursion
●
●
●
Neue Denkweise
Wikipedia: “Als Rekursion bezeichnet man den
Aufruf oder die Definition einer Funktion durch
sich selbst.”
Rekursion ist
eine Form der Wiederholung
●
Rekursion ermöglicht
●
elegante Algorithmen
●
Komplexitätsanalyse
Rekursion
●
Beginn der Fibonacci-Folge:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, . . .
●
Rekursive Definition der Fibonacci-Folge:
a. fib(n) = 0, wenn n = 0
b. fib(n) = 1, wenn n = 1
c. fib(n) = fib(n − 1)+fib(n − 2), wenn n ≥ 2
●
●
Die Rekursion in (2) stoppt, wenn n = 0 oder n
= 1.
Abbruchbedingung?
Rekursion
●
Fibonacci-Definition in Python
Fibonacci-Zahlen
Zu
Beginn
eines
Jahres gibt es genau
ein Paar neugeborener
Kaninchen.
Dieses
Paar wirft nach 2
Monaten ein neues
Kaninchenpaar
und
dann monatlich jeweils
ein weiteres Paar.
Jedes
neugeborene
Paar vermehrt sich auf
die gleiche Weise.
Rekursion
●
der Fakultätsfunktion:
4! = 4 * 3 * 2 * 1
●
Rekursive Definition der Fakultätsfunktion:
a. faku(n) = 1, wenn n = 0
b. faku(n) = n * faku(n-1), wenn n > 0
●
Python:
Rekursion
●
Euklidischer Algorithmus des GGT:
a. ggT(x, y) = x, wenn y = 0
b. ggT(x, y) = ggT((x − y), y), wenn x > y
c. ggT(x, y) =ggT(x,(y − x)) wenn x ≤ y
●
GGT = größter gemeinsamer Teiler.
●
Sie stoppt, wenn y = 0
Rekursion
●
Euklidischer Algorithmus in Python
Rekursion
●
●
Abbruchbedingung?
Analog zu unendlichen Schleifen mit for- and
while- Schleifen
Rekursion vs. Iteration
●
●
●
Rekursive Algorithmen sind oft natürlicher und
einfacher zu finden als iterative
Die Korrektheit rekursiver Algorithmen ist oft
einfacher zu prüfen
Rekursive Lösungen sind i.A. statisch kürzer
und – auch weil verständlicher –
änderungsfreundlicher
Rekursion vs. Iteration
●
Jeder rekursive Algorithmus kann in einen
iterativen transformiert werden, indem man den
rekursiven Aufruf mit Laufzeitkeller simuliert
Rekursion vs. Iteration
●
Von Iteration zu Rekursion
Rekursion in Mathematik
die rekursiv konstruierten Dreiecke finden sich
in der Gesamtstruktur wieder
Rekursion in Mathematik
Pythagoras-Baum
Auf einem Quadrat wird auf der Oberseite ein Thaleskreis
gezeichnet und dieser beliebig geteilt. Der entstehende Punkt
wird mit dem Grundelement verbunden, so dass ein
rechtwinkliges Dreieck entsteht. Aus den beiden entstandenen
Schenkeln des Dreiecks wird wieder jeweils ein Quadrat
konstruiert. An den beiden entstandenen Quadraten wird der
Vorgang wiederholt.
Rekursion in Mathematik
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);
}
Rekursion in Natur
●
Romanescogemüse
Rekursion in Kunst
●
Droste Effect
Vorteile rekursiver Algorithmen
●
kürzere Formulierung
●
leichter verständliche Lösung
●
Einsparung von Variablen
●
●
teilweise sehr effiziente Problemlösungen (z.B.
Quicksort)
Bei rekursiven Datenstrukturen (zum Beispiel
Bäume, Graphen) besonders empfehlenswert
Nachteile rekursiver Algorithmen
●
●
●
weniger effizientes Laufzeitverhalten (Overhead
bei Funktionsaufruf)
Verständnisprobleme bei Programmieranfängern
Konstruktion rekursiver Algorithmen
"gewöhnungsbedürftig"
Komplexität
Beurteilung von Algorithmen
●
●
●
viele Algorithmen, um dieselbe Funktion zu
realisieren
Welche Algorithmen sind die besseren?
nicht-funktionaler Eigenschaften:
●
●
Zeiteffizienz: Wie lange dauert die Ausführung?
Speichereffizienz: Wie viel Speicher wird zur
Ausführung benötigt?
●
Benötigte Netzwerkbandbreite
●
Einfachheit des Algorithmus
●
Aufwand für die Programmierung
Ressourcenbedarf
●
●
Prozesse verbrauchen:
●
Rechenzeit
●
Speicherplatz
Die Ausführungszeit hängt ab von:
●
der konkreten
Programmierung
●
Prozessorgeschwindigkeit
●
Programmiersprache
●
Qualität des Compilers
Beispiel
Leistungsverhalten von Algorithmen
●
●
●
●
Speicherplatzkomplexität: Wird primärer &
sekundärer Speicherplatz effizient genutzt?
Laufzeitkomplexität: Steht die Laufzeit im
akzeptablen / vernünftigen / optimalen
Verhältnis zur Aufgabe?
Theorie: liefert untere Schranke, die für jeden
Algorithmus gilt, der das Problem löst
Spezieller Algorithmus liefert obere Schranke
für die Lösung des Problems
Laufzeit
Die Laufzeit T(x) eines Algorithmus A bei
Eingabe x ist definiert als die Anzahl von
Basisoperationen, die Algorithmus A zur
Berechnung der Lösung bei Eingabe x benötigt
●
Ziel: Laufzeit = Funktion der Größe der Eingabe
http://xkcd.com/399/
Laufzeit
●
●
●
Sei P ein gegebenes Programm und x Eingabe
für P, |x| Länge von x, und T(x) die Laufzeit von
P auf x
Ziel: beschreibe den Aufwand eines
Algorithmus als Funktion der Größe des Inputs
Der beste Fall:
T(n) = inf {T(x) | |x| = n, x Eingabe für P}
●
Der schlechteste Fall:
T(n) = sup {T(x) | |x| = n, x Eingabe für P}
Minimum-Suche
●
Eingabe: Array von n Zahlen
●
Ausgabe: index i, so dass a[i]<a[j], für alle j
Minimum-Suche
Kosten:
c1
c2
c3
c4
Max Anzahl:
1
n-1
n-1
n-1
Zeit:
T(n) = c1 + (n-1) (c2+c3+c4)< c5n + c1
n= Größe des Arrays
Weiteres Beispiel
●
Wir betrachten folgenden Algorithmus, der die
Funktion
f(n) = 1! * 2! * ... * (n-2)! * (n-1)!
Weiteres Beispiel
●
Anzahl M(n):
M(n) = (n-1) + M(n-1)= (n-1) + (n-2) + M(n-2) = (n-1)
(n-2)/2
●
Anzahl der Inkrementierungen:
I(n) = n + M(n+1)=n(n+1)/2
●
Anzahl der Vergleiche
V(n) = I(n+1) = (n+1)(n+2)/2
●
Die Anzahl benötigter Zuweisungen Z(n):
Z(n) = 1 + n + I(n) = 1 + n(n+3)/2
Algorithmisches Modell
●
Für eine präzise mathematische Laufzeitanalyse
benötigen wir ein Rechenmodell, das definiert
●
Welche Operationen zulässig sind.
●
Welche Datentypen es gibt.
●
Wie Daten gespeichert werden.
●
●
Wie viel Zeit Operationen auf bestimmten Daten
benötigen.
Formal ist ein solches Rechenmodell gegeben
durch die Random Accsess Maschine (RAM)
Basisoperationen und deren Kosten
●
●
Als Basisoperationen bezeichnen wir:
●
Arithmetische Operationen
●
Datenverwaltung
●
Kontrolloperationen
Kosten: Zur Vereinfachung nehmen wir an, daß
jede dieser Operationen bei allen Operanden
gleich viel Zeit benötigt
Asymptotische Komplexität
●
●
●
Laufzeit und Speicherverbrauch wird in einer
asymptotischen Notation beschrieben, die
weitgehend von unwesentlichen Details
abstrahiert.
Sie macht nur Aussagen über das Verhalten für
„sehr große“ Eingabegrößen.
Vergleich von zwei Komplexitätsfunktionen über
alle natürlichen Zahlen ist nicht ganz einfach
Asymptotische Komplexität
●
Vergleich von zwei Komplexitätsfunktionen über
alle natürlichen Zahlen ist nicht ganz einfach
Wir übernehmen eine mathematische Notation,
die zum Vergleichen von Funktionen a) bis auf
einen Faktor und b) bis auf eine endliche
Anzahl von Ausnahmen verwendet wird
Asymptotische Komplexität
●
●
Groß-Oh-Notation: bringt zum Ausdruck, dass
eine Funktion f(n) höchstens so schnell wächst
wie eine andere Funktion g(n). g(n) Ist also die
obere Schranke für f(n).
Funktion f(n) ist in der
Menge O(g(n)), wenn es
ein c > 0 und ein n0 ∈ N gibt,
so dass für alle n ≥ n0 gilt:
f(n) ≤ c . g(n)
Asymptotische Komplexität
●
O-Notation: Abstraktion durch
●
●
●
Ignorieren endlich vieler Anfangswerte (Spezialfälle)
durch n ≥ n0
Einführung des konstanten Faktors c in der
Definition, der von nur durch Konstanten
hervorgerufenen Unterschieden abstrahiert
Beispiel:
●
●
T1(n) = 100 * n ∈ O(n): T1(n) wächst höchstens so
schnell wie n
T2(n) = n*n ∈ O(n*n): T2(n) wächst höchstens so
schnell wie n*n
Asymptotische Komplexität
Häufige Größenordnung der Komplexität:
●
●
●
●
●
●
O(1): In konstanter (von n unabhängiger) Zeit
ausführbar
O(log n): Bei Verdoppelung von n läuft das
Programm um eine konstante Zeit länger
O(n) Linear: Laufzeit proportional zu n
O(n*n): Quadratische Laufzeit; z. B. wenn je zwei
Datenelemente zu kombinieren sind
O(n^3): Kubische Laufzeit; nur für kleinere n
geeignet
O(2^n): Exponentielles Wachstum; solche
Programme sind in der Praxis fast immer wertlos
Asymptotische Komplexität
●
Groß-Omega-Notation: bringt zum Ausdruck,
dass eine Funktion f(n) mindestens so schnell
wächst wie eine andere Funktion g(n). g(n) Ist
also die untere Schranke für f(n).
●
Definition: Funktion f(n) ist
in der Menge Ω(g(n)),
wenn es ein c > 0 und
ein n0 ∈ N gibt, so dass für alle
n ≥ n0 gilt: f(n) ≥ c . g(n)
Asymptotische Komplexität
●
●
Gross-Theta-Notation: Wenn eine Funktion f(n)
sowohl von oben als auch von unten durch g(n)
beschränkt ist, so schreibt man f(n) = Ө (g(n)).
Formal ist die Menge Ө(g(n))
definiert durch
Ө(g(n)) = O(g(n)) ∩ Ω(g(n)) g(n)
Ist also die exakte
Schranke für f(n).
Beispiele
Herunterladen