Algorithmen und Datenstrukturen

Werbung
Was bisher geschah
I
Definition Algorithmus
I
Eigenschaften von Algorithmen
I
Spezifikation von Berechnungsproblemen
I
Instanzen von Berechnungsproblemen
I
Spezifikation des Sortierproblemes
I
Korrektheit von Algorithmen
I
Algorithmenentwurf:
Spezifikation, Entwurf, Verifikation
I
Laufzeit von Algorithmen
I
O-Notation
43
Rekursive Algorithmen
Basisfall (Induktionsanfang): direkte Lösung
Rekursionsschritt (Induktionsschritt):
Funktionswert wird aus den Funktionswerten derselben
Funktion mit anderen (einfacheren) Argumenten berechnet
Beispiele:
I Fakultät
1
falls n = 0
n! =
n(n − 1)! sonst
I
I
I
Fibonacci-Funktion

falls n = 0
 0
1
falls n = 1
f (n) =

f (n − 1) + f (n − 2) sonst
I
Ackermann-Funktion

falls x = 0
 y +1
a(x − 1, 1)
falls y = 0 und x > 0
a(x, y ) =

a(x − 1, a(x, y − 1)) sonst
44
Funktionale Programmiersprache Haskell
(statt Pseudocode)
Haskell-Interpreter zum Ausprobieren:
I
ghc / ghci (http://www.haskell.org/ghc/)
I
Hugs (www.haskell.org/hugs/)
fac :: Int -> Int
fac 0 = 1
fac n = n * fac (n-1)
fib
fib
fib
fib
:: Int -> Int
0 = 1
1 = 1
n = fib (n-1) + fib (n-2)
ack
ack
ack
ack
:: Int ->
0 y = y +
x 0 = ack
x y = ack
Int -> Int
1
(x-1) 1
(x-1) (ack x (y-1))
45
Laufzeit-Berechnung für n!
Algorithmus : fac
Eingabe : x
Ausgabe : y
Spezifikation:
V: x ∈
wenn x = 0 dann
y ←1
sonst
y ← x fac(x − 1)
N
N: y = x!
T (n)
Rekurrenz T (0)
=
1
T (n)
=
T (n − 1) + 1
=
=
T (n − 1) + 1
(T (n − 2) + 1) + 1 = T (n − 2) + 2
=
T (n − 3) + 3
...
=
Laufzeit O(n)
T (n − n) + n = T (0) + n = 1 + n
46
Divide-and-Conquer-Verfahren
(teile und herrsche)
Idee: rekursive Zerlegung des Problemes in Teilprobleme
bis zum Basisfall
Grundprinzip:
Teilung des Problems P in n Teilprobleme Pi
Lösung aller Teilprobleme Pi (Rekursion)
Kombination der Lösungen der Teilprobleme Pi zu einer
Lösung des Problems P
(Baumstruktur)
47
Beispiel: Suche in sortierten Folgen
Spezifikation des Suchproblemes in sortierten Folgen:
V: Eingaben x = (x1 , . . . , xn ) aufsteigend sortiert, y
N: Ausgabe:
I Ja, falls ein i ∈ {1, . . . , n} mit xi = y existiert,
I sonst Nein
Algorithmus : Suche3
Eingabe : (x1 , . . . , xn ), y und l, r ∈ {1, . . . , n} (Bereichsgrenzen
Ausgabe : gefunden
wenn l > r dann gefunden ← Nein
sonst
m ← b(l + r )/2c
wenn xm = y dann gefunden ← Ja
sonst
wenn xm < y dann Suche3(x, y , m + 1, r )
sonst Suche3(x, y , l, m − 1)
48
Laufzeit: Suche in sortierten Folgen
T (0) = a
T (n) = T (bn/2c) + b
für n = 2k , also k = log n:
T (n)
=
T (n/21 ) + b
=
T (n/22 ) + b + b
=
T (n/23 ) + 3b
...
=
T (n/2k ) + kb = a + k b
Laufzeit: O(log n)
49
Klassisches Beispiel: Türme von Hanoi
I
Positionen A, B.C
I
n Scheiben {1, . . . , n} der Größen 1, . . . , n
I
Bedingung:
Scheibe i darf nur dann auf Scheibe j liegen, wenn i < j
zulässige Bewegungen (zusammen ein Zug):
I
I
I
Nimm die obere Scheibe i von Position x ∈ {A, B, C} und
Lege diese Scheibe i auf Position y ∈ {A, B, C}, sofern
damit auf Position y die Bedingung nicht verletzt wird
I
Startsituation:
Auf Position A ein Turm aus n (zulässig) gestapelten
Scheiben, Positionen B, C leer
I
Zielsituation:
Auf Position B ein Turm aus n (zulässig) gestapelten
Scheiben, Positionen A, C leer
gesucht: Folge von Schritten vom Start- zum Zielzustand
50
Türme von Hanoi: rekursiver Algorithmus
Verschiebe einen Hanoi-Turm der Höhe n von Position A zu
Position B, falls nötig, unter Verwendung der Position C:
Spezifikation:
V: (x : n, y : 0, z : 0), l = ()
N: (x : 0, y : n, z : 0),
l enthält die Folge aller Züge
(Start- und Zielposition der bewegten Scheibe)
Algorithmus Hanoi(x, y , z):
Basisfall: n = 0 (keine Bewegung)
Rekursionsschritt: 1. die oberen n − 1 Scheiben von Position
x zu Position z verschieben, falls nötig, unter
Verwendung der Position y (rekursiv),
2. Verschiebe die größte Scheibe von Position x
zu Position y ,
Zug (x → y ) an l anhängen
3. die n − 1 Scheiben von Position z zu Position
y verschieben, falls nötig, unter Verwendung
der Position x (rekursiv).
51
Türme von Hanoi in Haskell
Datentyp für die Positionen:
data Platz = A | B | C
deriving Show
hanoi :: Int -> Platz -> Platz -> Platz
-> [ ( Platz , Platz ) ]
hanoi 0 von nach hilf = []
hanoi n von nach hilf =
hanoi ( n - 1 ) von hilf nach
++ [ ( von , nach ) ]
++ hanoi ( n - 1 ) hilf nach von
52
Türme von Hanoi: Laufzeit
Laufzeit: Anzahl der Bewegungen
T (0) = 0
T (n) = 2T (n − 1) + 1
T (n)
=
2T (n − 1) + 1
=
2(2T (n − 2) + 1) + 1 = 4T (n − 2) + 3
=
2(2(2T (n − 3) + 1) + 1) + 1 = 8T (n − 2) + 7
...
=
2n T (0) +
n
X
2i−1 = 2n − 1
i=0
Laufzeit des Algorithmus: O(2n )
53
Häufig vorkommende Rekurrenzen
T (n) = T (n − 1) + 1
T (n) = T (n − 1) + n
T (n) = T (n/2) + 1
T (n) = T (n/2) + n
T (n) = 2T (n/2) + 1
T (n) = 2T (n − 1) + 1
. . . = T (0) + n
. . . = T (0) + n2
. . . = T (0) + log n
. . . = T (0) + n log n
. . . = 2log n T (0) + 2log n log n
O(n)
O(n2 )
O(log n)
O(n log n)
O(n log n)
O(2n )
54
Herunterladen