Grundlagen der Programmierung 4 [1.5ex] Haskell: Bäume [1.5ex

Werbung
Datenstruktur Baum
Grundlagen der Programmierung 4
Binäre, geordnete Bäume in Haskell:
Haskell: Bäume
Prof. Dr Manfred Schmidt-Schauß
data Binbaum a = Bblatt a | Bknoten (Binbaum a) (Binbaum a)
•
•
•
Daten (Markierungen) sind an den Blättern des Baumes
Jeder (innere) Knoten hat genau zwei Tochterknoten
es gibt linken und rechten Tochterknoten (geordnet)
Sommersemester 2013
1
Grundlagen der Programmierung 2 Bäume)
Datenstruktur Baum; Beispiel
Datenstruktur Baum; Beispiel
Der folgende binäre Baum
Bknoten (Bknoten (Bblatt 1)
(Bknoten (Bblatt 3) (Bblatt 4)))
(Bknoten (Bblatt 7) (Bblatt 8))
·
·t
1

3
·
7
– 2/16 –
·
Als Syntaxbaum:
8
Bknoten
4
Bknoten
hat eine Darstellung als
x
1
w
BBlatt
– 3/16 –
w
Bknoten
3
Grundlagen der Programmierung 2 Bäume)
Bknoten
'
BBlatt
Bknoten (Bknoten (Bblatt 1)
(Bknoten (Bblatt 3) (Bblatt 4)))
(Bknoten (Bblatt 7) (Bblatt 8))
'
r
Grundlagen der Programmierung 2 Bäume)
BBlatt
&
BBlatt
&
BBlatt
7
8
4
– 4/16 –
Einige Verarbeitungsfunktionen
Einige Verarbeitungsfunktionen (2)
Rand: Liste der Markierungen der Blätter:
Größe des Baumes:
b_rand (Bblatt x)
= [x]
b_rand (Bknoten bl br) = (b_rand bl)
++ (b_rand br)
testet, ob eine Markierung existiert:
b_in x (Bblatt y)
= (x == y)
b_in x (Bknoten bl br) = b_in x bl
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)
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äume)
b_size (Bblatt x)
=
b_size (Bknoten bl br) =
Tiefe des Baumes:
(b_map f br)
– 5/16 –
Einige Verarbeitungsfunktionen (3)
b_depth (Bblatt x) = 0
b_depth (Bknoten bl br) =
1 + (max (b_depth bl) (b_depth br))
Grundlagen der Programmierung 2 Bäume)
– 6/16 –
Auswertung mit foldbt
schnelles fold über binäre Bäume:
Werte foldbt (+) 0
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)
<<<1,2>,3>,<4 ,5>> aus:
(+) 0 <<<1,2>,3>,<4,5>>
(+) (foldbt (+) 0 <4,5>) <<1,2>,3>
(+) (foldbt (+) (foldbt (+) 0 <5>) <4>) <<1,2>,3>
(+) (foldbt (+) (5 + 0) <4>) <<1,2>,3>
(+) (4 + (5 +0)) <<1,2>,3>
(+) (foldbt (+) (4 + (5 + 0)) <3>) <1,2>
(+) (3 + (4 + (5 + 0))) <1,2>
(+) (foldbt (+) (3 + (4 + (5 + 0))) <2>) <1>)
(+) (2 + (3 + (4 + (5 + 0)))) <1>
+ (3 + (4 + (5 + 0))))
(Der Baum ist vereinfacht als Tupel von Tupeln mit dargestellt)
tatsächlicher Aufruf nach Laden des Programmfiles
effizientere Version von b rand und b sum
b_rand_eff = foldbt (:) []
b_baum_sum’ = foldbt’ (+) 0
Grundlagen der Programmierung 2 Bäume)
foldbt
foldbt
foldbt
foldbt
foldbt
foldbt
foldbt
foldbt
foldbt
1 + (2
foldbts (+) 0 (Bk (Bk (Bk (Bb 1) (Bb 2)) (Bb 3)) (Bk (Bb 4) (Bb 5)))
– 7/16 –
Grundlagen der Programmierung 2 Bäume)
– 8/16 –
Bemerkungen zu foldbt
Suchbaum
Effizienzsteigerung beim Zugriff auf Elemente einer Liste:
Sei tr binärer Baum mit Randliste [a1 , . . . , an ]
sortierte Liste als Baum
(foldbt f a tr) entspricht
(f a_1 (f a_2 (... (f a_n a) ...s))).
Jeder Knoten enthält als Markierung den größten Schlüssel
seines linken Teilbaumes
D.h. foldbt entspricht foldr
Laufzeit des Such-Zugriffs:
logarithmisch in der Anzahl der Elemente
Grundlagen der Programmierung 2 Bäume)
– 9/16 –
Suchbaum, Beispiel
Grundlagen der Programmierung 2 Bäume)
– 10/16 –
Haskell-Implementierung: Suchbaum
5
1u
1
3
Grundlagen der Programmierung 2 Bäume)
3
7
data Satz a
= Satz Integer a
data Suchbaum a =
Sblatt Integer a
| Sknoten (Suchbaum a) Integer (Suchbaum a)
| Suchbaumleer
7
11
Verwendung:
Suchbaum (Satz a)
5
– 11/16 –
Grundlagen der Programmierung 2 Bäume)
– 12/16 –
Haskell-Implementierung: Suchbaum
Haskell-Implementierung zum 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)
Elementweises Einfügen :
sortiert die Eingabe
Vorsicht:
Der naiv erzeugte Baum kann
unbalanciert sein!
das bewirkt Verschlechterung der Laufzeit
von O(log(n)) auf O(n)
Abhilfe:
Balancieren des Baumes durch Rotationen
zusammen mit dem Einfügen
Laufzeit des Baumaufbaus
mit Balancieren:
Grundlagen der Programmierung 2 Bäume)
– 13/16 –
Haskell-Library zu Suchbäumen
– 14/16 –
mit beliebiger Anzahl Töchter
Die Programmierung ist analog zu einfachen Bäumen
implementiert balancierte Suchbäume in Haskell:
(Schlüssel,Wert) - Paare, so dass pro Schlüssel nur ein Paar
vorkommt.
data Nbaum a = Nblatt a | Nknoten [Nbaum a]
erzeugt Suchbaum mit einem (Schlüssel, Wert)-Paar
fügt ein Eement ein.
löscht ein Element zu gegebenem Schlüssel.
findet ein Element zu gegebenem Schlüssel
ändert Wert zu gegebenem Schlüssel
Grundlagen der Programmierung 2 Bäume)
Grundlagen der Programmierung 2 Bäume)
Allgemeinere Bäume
Data.Map
Funktionen:
singleton
insert
delete
lookup
adjust
O(n ∗ log(n))
– 15/16 –
nbaumrand :: Nbaum a -> [a]
nbaumrand
(Nblatt x) = [x]
nbaumrand
(Nknoten xs) = concatMap nbaumrand xs
Grundlagen der Programmierung 2 Bäume)
– 16/16 –
Herunterladen