Grundlagen der Programmierung 2 Bäume Prof. Dr. Manfred Schmidt-Schauÿ Künstliche Intelligenz und Softwaretechnologie 15. Mai 2007 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 - 1 - Datenstruktur Baum; Beispiel Der folgende binäre Baum 1 ~~ ~~ ~ ~~ ~ ~ · ii iiii i i i iiii iiii i i i ii tiiii >> >> >> >> >> < <<< << << < 3 · · ??? 7 ?? ?? ?? · >>> >> >> >> 8 4 hat eine Darstellung als Bknoten (Bknoten (Bblatt 1) (Bknoten (Bblatt 3) (Bblatt 4))) (Bknoten (Bblatt 7) (Bblatt 8)) Grundlagen der Programmierung 2 - 2 - 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 eine Markierung existiert: 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) - 3 - 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 - 4 - 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 - 5 - Auswertung mit foldbt Werte foldbt (+) 0 "(((1,2),3),(4 ,5))" aus: syntaktisch richtiger Aufruf: foldbts (+) 0 (Bk (Bk (Bk (Bb 1) (Bb 2)) (Bb 3)) (Bk (Bb 4) (Bb 5))) 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 foldbt foldbt foldbt foldbt 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) (4+ (5+0)))) (Der Baum ist auf dieser Folie vereinfacht dargestellt) Grundlagen der Programmierung 2 - 6 - 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 - 7 - 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 - 8 - Suchbaum, Beispiel 1 1 3 Grundlagen der Programmierung 2 jj jjjj j j j jjj jjjj j j j jjj jjjj j j j jjjj jjjj j j j tjjjj ?? ?? ?? ?? ?? ?? ?? ?? ? 3 ??? ?? ?? ?? ?? ?? ?? ?? 5 ??? ?? ?? ?? ?? ?? ?? ?? 7 7 AAA AA AA AA AA AA AA AA A 11 5 - 9 - 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 - 10 - 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 - 11 - 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 - 12 - 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 - 13 -