Grundlagen der Programmierung 2 Bäume

Transcrição

Grundlagen der Programmierung 2 Bäume
Grundlagen der Programmierung 2
Bäume
Prof. Dr. Manfred Schmidt-Schauÿ
Künstliche Intelligenz und Softwaretechnologie
24. Mai 2006
Graphen
Graph:
Menge von Knoten undzugehörige
(gerichtete oder ungerichtete) Kanten zwischen den
Knoten
Einige Begriffe für ungerichtete Graphen
Schlingen
Wege
Kreise
Erreichbarkeit
zusammenhängend:
markierter Graph
Grundlagen der Programmierung 2
Kanten mit gleichem Anfangs- und Endknoten
Kantenfolgen (A, B), (B, C), . . .
Kantenfolgen (A, B), (B, C), . . . , (Z, A)
A ist von B aus erreichbar, wenn es einen Weg von
A nach B gibt
alle Knoten sind von jedem Knoten aus erreichbar
Knoten bzw. Kanten haben Markierungen
- 1 -
Bäume
Baum:
ein (gerichteter oder ungerichteter) Graph,
zusammenhängend, ohne Kreise, mit Wurzel-Knoten
Annahme: die Wurzel ist oben,
Wurzel
Vorgänger
Blatt
Tochter
Nachfolger
Grundlagen der Programmierung 2
- 2 -
Bäume: Einige Begriffe:
geordneter Baum
markierter Baum
Rand des Baumes
binärer Baum
Höhe (Tiefe)
balanciert
Grad eines Knoten
Grad eines Baumes
Grundlagen der Programmierung 2
Links-Rechts-Ordnung auf den Töchtern (Kinder,Söhne)
Die Knoten haben Markierung (bzw. Kanten)
Liste der Blattmarkierungen eines geordneten Baumes
Jeder Knoten ist Blatt oder hat genau zwei Töchter
maximale Länge eines Weges von der Wurzel zu
einem Blatt
bei gleichem Rand kleinste Tiefe (eines binären
Baumes)
Anzahl der Töchter
maximaler Grad eines Knoten
- 3 -
Datenstruktur Baum
Binäre, geordnete Bäume in Haskell:
data Binbaum a = Bblatt
•
•
•
•
a | Bknoten (Binbaum a) (Binbaum a)
Daten (Markierungen) sind an den Blättern des Baumes
Die Daten sind von gleichem Typ
Jeder (innere) Knoten hat genau zwei Tochterknoten
es gibt linken und rechten Tochterknoten (geordnet)
Grundlagen der Programmierung 2
- 4 -
Datenstruktur Baum; Beispiel
Der folgende binäre Baum
1
7
3
8
4
hat eine Darstellung als
Bknoten (Bknoten (Bblatt 1)
(Bknoten (Bblatt 3) (Bblatt 4)))
(Bknoten (Bblatt 7) (Bblatt 8))
Grundlagen der Programmierung 2
- 5 -
Einige Verarbeitungsfunktionen
Rand: Liste der Markierungen der Blätter:
b_rand (Bblatt x)
= [x]
b_rand (Bknoten bl br) = (b_rand bl)
++ (b_rand br)
testet, ob Element im Baum ist:
b_in x (Bblatt y)
= (x == y)
b_in x (Bknoten bl br) = b_in x bl
||
b_in x br
wendet eine Funktion auf alle Elemente des Baumes an,
Resultat: Baum der Resultate
b_map f (Bblatt x)
= Bblatt (f x)
b_map f (Bknoten bl br) =
Bknoten (b_map f bl)
Grundlagen der Programmierung 2
(b_map f br)
- 6 -
Einige Verarbeitungsfunktionen (2)
Größe des Baumes:
b_size (Bblatt x)
=
b_size (Bknoten bl br) =
1
1+ (b_size bl) + (b_size br)
Summe aller Blätter, falls Zahlen:
b_sum (Bblatt x)
= x
b_sum (Bknoten bl br) = (b_sum bl) + (b_sum br)
Tiefe des Baumes:
b_depth (Bblatt x) = 0
b_depth (Bknoten bl br) =
1 + (max (b_depth bl) (b_depth br))
Grundlagen der Programmierung 2
- 7 -
Einige Verarbeitungsfunktionen (3)
schnelles fold über binäre Bäume:
foldbt :: (a -> b -> b) -> b -> Binbaum a -> b
foldbt op a (Bblatt x)
= op x a
foldbt op a (Bknoten x y) = (foldbt op (foldbt op a y) x)
foldbt mit optimiertem Stackverbrauch:
foldbt’ :: (a -> b -> b) -> b -> Binbaum a -> b
foldbt’ op a (Bblatt x)
= op x a
foldbt’ op a (Bknoten x y) = (((foldbt’ op) $! (foldbt’ op a y)) x)
effizientere Version von b rand und b sum
b_rand_eff = foldbt (:) []
b_baum_sum’ = foldbt’ (+) 0
Grundlagen der Programmierung 2
- 8 -
Auswertung mit foldbt
Werte foldbt (+) 0 "(((1,2),3),(4 ,5))" aus:
foldbt (+) 0 "(((1,2),3),(4 ,5))"
--> foldbt (+) (foldbt (+) 0 (4 ,5))
((1,2),3)
--> foldbt (+) (foldbt (+) (foldbt (+) 0 (5)) (4)
((1,2),3))
--> foldbt (+) (foldbt (+) (5+0) (4)
((1,2),3))
--> foldbt (+) (4+ (5+0))
((1,2),3)
--> foldbt (+) (foldbt (+) (4+ (5+0))
(3)) (1,2)
--> foldbt (+) (3+ (4+ (5+0)))
(1,2)
--> foldbt (+) (foldbt (+) (3+ (4+ (5+0))) (2) (1))
--> foldbt (+) (2+ (3+ (4+ (5+0)))) (1)
--> 1+ (2+ (3+ (4+ (5+0))))
Grundlagen der Programmierung 2
- 9 -
Bemerkungen zu foldbt
Sei tr binärer Baum mit Randliste [a1, . . . , an]
(foldbt f a tr) entspricht (f a_1
(f a_2 (... (f a_n a) ...s))).
D.h. foldbt entspricht foldr
Grundlagen der Programmierung 2
- 10 -
Vergleich von b rand und b rand eff :
Nur für volle binäre Bäume: testbaum m
Ergebnislisten werden voll ausgewertet
Zählweise der Reduktionen wie in Hugs
Grundlagen der Programmierung 2
- 11 -
Analyse von b rand:
#Reduktionen von (b_rand testbaum_n)
Tiefe #Blätter #berechnet
m
2m
2m + 2m−1 ∗ m + 3 ∗ 2m
n
n + n/2 ∗ log2(n) + 3 ∗ n
10
1024
9216
12
4096
40960
13
8192
86016
14
16384
180224
Grundlagen der Programmierung 2
#tatsächliche
2m + 2m−1 ∗ m + 3 ∗ 2m + 14
n + n/2 ∗ log2(n) + 3 ∗ n + 14
9230
40974
86030
180238
- 12 -
Analyse von b rand eff
#Reduktion von (b_rand_eff testbaum_n)
Tiefe #Blätter #berechnet
m
2m
2m + 2 ∗ 2m
n
3n
10
1024
1072
12
4096
12288
13
8192
24576
14
16384
49152
Fazit:
#tatsächliche
2m + 2 ∗ 2m + 15
3n + 15
3087
12303
24591
49167
#Red(b rand)
9230
40974
86030
180238
b rand eff ist effizienter:
O(n) statt O(n ∗ log(n)).
Grundlagen der Programmierung 2
- 13 -
Suchbaum
Effizienzsteigerung beim Zugriff auf Elemente:
sortierte Liste als Baum
Jeder Knoten enthält als Markierung den größten Schlüssel des linken
Teilbaumes mit den kleineren Werten.
Laufzeit des Zugriffs: logarithmisch in der Anzahl der Elemente
Grundlagen der Programmierung 2
- 14 -
Suchbaum, Beispiel
5
7
1
7
1
11
3
3
Grundlagen der Programmierung 2
5
- 15 -
Haskell-Implementierung: Suchbaum
data Satz a
= Satz Integer
a
data Suchbaum a =
Sblatt Int a
| Sknoten (Suchbaum a) Int (Suchbaum a)
| Suchbaumleer
Verwendung:
Suchbaum (Satz a)
intial = Suchbaumleer
Grundlagen der Programmierung 2
- 16 -
Haskell-Implementierung: Suchbaum
einfuegeDbS (Satz x sx) Suchbaumleer = Sblatt x (Satz x sx)
einfuegeDbS (Satz x sx) (Sblatt k satzk) =
if x < k
then Sknoten (Sblatt x (Satz x sx)) x (Sblatt k satzk)
else if x == k then error " schon eingetragen"
else Sknoten (Sblatt k satzk) k (Sblatt x (Satz x sx))
einfuegeDbS (Satz x sx) (Sknoten l k r) =
if x < k then Sknoten (einfuegeDbS (Satz x sx) l) k r
else if x == k then error " schon eingetragen"
else Sknoten l k (einfuegeDbS (Satz x sx) r)
Grundlagen der Programmierung 2
- 17 -
Haskell-Implementierung zum Suchbaum
Elementweises Einfügen :
sortiert die Eingabe
Vorsicht:
Der entstehende Baum kann
unbalanciert sein
bewirkt Verschlechterung der Laufzeit
von O(log (n)) auf O(n)
Abhilfe:
Balancieren des Baumes durch Rotationen
Laufzeit des Baumaufbaus
mit Balancieren:
O(n ∗ log (n))
Grundlagen der Programmierung 2
- 18 -
Haskell-Implementierung eines Suchbaumes (2)
istinDbS (Satz x y) Suchbaumleer = False
istinDbS (Satz x y) (Sblatt k _)
= (x == k)
istinDbS (Satz x y) (Sknoten bl k br) =
if x < k then istinDbS (Satz x y) bl
else if x == k then True
else istinDbS (Satz x y) br
erzeugeDbS [] = Suchbaumleer
erzeugeDbS (x:xs) = einfuegeDbS (Satz x x)
druckeDbS sb = blaetterSB
Grundlagen der Programmierung 2
(erzeugeDbS xs)
- 19 -
Haskell-Implementierungen zum Suchbaum
foldSB
foldSB
foldSB
foldSB
::
op
op
op
(a -> b -> b) -> b -> Suchbaum a -> b
a Suchbaumleer = a
a (Sblatt _ x) = op x a
a (Sknoten x _ y) = (foldSB op (foldSB op a y) x)
blaetterSB = foldSB (:) []
Grundlagen der Programmierung 2
- 20 -
Allgemeinere Bäume
mit beliebiger Anzahl Töchter
Die Programmierung ist analog zu einfachen Bäumen
data Nbaum a = Nblatt a | Nknoten [Nbaum a]
nbaumrand :: Nbaum a -> [a]
nbaumrand
(Nblatt x) = [x]
nbaumrand
(Nknoten xs) = concatMap nbaumrand xs
Grundlagen der Programmierung 2
- 21 -