Gliederung Einführung Binary Tree Binary Search Tree Binary Heap Rose Tree Anwendungsbeispiel: Huffman Tree 09.04.2019
Einführung Was sind Bäume? Bäume sind spezielle Graphen Diese Graphen sind zusammenhängend Besitzen einen Wurzelknoten Jeder nicht Wurzelknoten, besitzt genau einen Elternknoten Knoten können beliebig viele Nachkommen haben Knoten ohne Nachkommen werden als Blätter bezeichnet 09.04.2019
Einführung Wozu werden Bäume benötigt? Generalisierung von Listen Hierarchische Strukturen aufbauen Effiziente Verarbeitung von Daten 09.04.2019
Binary Tree Knoten haben genau zwei Kinder oder sind Blätter Definition in Haskell data Btree a = Leaf a | Fork (Btree a) (Btree a) Eigenschaften Größe ist die Anzahl der Blätter Tiefe ist die Distanz von der Wurzel zum weitesten entfernten Blatt Anzahl innerer Knoten entspricht der Größe vermindert um eins 09.04.2019
Binary Tree Berechnung der Eigenschaften size :: Btree a -> Int size (Leaf x) = 1 size (Fork xt yt) = size xt + size yt height :: Btree a -> Int height (Leaf x) = 0 height (Fork xt yt) = 1 + max (height xt) (height yt) nodes :: Btree a -> Int nodes (Leaf x) = 0 nodes (Fork xt yt) = 1 + nodes xt + nodes yt 09.04.2019
Binary Tree Baum -> Liste Liste -> Baum flatten :: Btree a -> [a] flatten (Leaf x) = [x] flatten (Fork xt yt) = flatten xt ++ flatten yt Liste -> Baum mkBtree :: [a] -> Btree a mkBtree xs | (m == 0) = Leaf (unwrap xs) | otherwise = Fork (mkBtree ys) (mkBtree zs) where m = (length xs) ‘div‘ 2 (ys, zs) = splitAt m xs 09.04.2019
Binary Tree map auf Bäumen fold auf Bäumen mapBtree :: (a -> b) -> Btree a -> Btree b mapBtree f (Leaf x) = Leaf (f x) mapBtree f (Fork xt yt) = Fork (mapBtree f xt) (mapBtree f yt) fold auf Bäumen foldBtree :: (a -> b) -> (b -> b -> b) -> Btree a -> b foldBtree f g (Leaf x) = f x foldBtree f g (Fork xt yt) = g (foldBtree f g xt) (foldBtree f g yt) 09.04.2019
Binary Tree Definitionen mit Fold size = foldBtree (const 1) (+) height = foldBtree (const 0) (\ a b -> 1 + max a b) flatten = foldBtree wrap (++) mapBtree f = foldBtree (Leaf . f) Fork 09.04.2019
Binary Search Tree Daten sind in den inneren Knoten enthalten Die Daten müssen ordinalen Typs sein Es gibt keine Blätter Definition in Haskell data (Ord a) => Stree a = Null | Fork (Stree a) a (Stree a) Für alle Elemente im linken Teilbaum gilt <a Für alle Elemente im rechten Teilbaum gilt >a 09.04.2019
Binary Search Tree Baum -> Liste Liste -> Baum flatten :: (Ord a) =>Stree a -> [a] flatten Null = [] flatten (Fork xt x yt) = flatten xt ++ [x] ++ flatten yt Liste -> Baum mkStree :: (Ord a) => [a] -> Stree a mkStree [] = Null mkStree (x:xs) = Fork (mkStree smaller) x (mkStree larger) where (smaller,larger) = partition (<x) xs partition :: (a->Bool) -> [a] -> ([a],[a]) partition p xs = ([ x | x <- xs, p x], [ y | y <- xs, (not . p) y]) 09.04.2019
Binary Search Tree Suchen Einfügen member :: (Ord a) => a -> Stree a -> Bool member x Null = False member x (Fork xt y yt) | (x < y) = member x xt | (x == y) = True | (x > y) = member x yt Einfügen insert :: (Ord a) => a -> Stree a -> Stree a insert x Null = Fork Null x Null insert x (Fork xt y yt) | (x < y) = Fork (insert x xt) y yt | (x == y) = Fork xt y yt | (x > y) = Fork xt y (insert x yt) 09.04.2019
Binary Search Tree Entfernen delete :: (Ord a) => a -> Stree a -> Stree a delete x Null = Null delete x (Fork xt y yt) | (x < y) = Fork (delete x xt) y yt | (x == y) = join xt yt | (x > y) = Fork xt y (delete x yt) join :: (Ord a) => Stree a -> Stree a -> Stree a join xt yt = if empty yt then xt else Fork xt h t where (h,t) = splitTree yt splitTree :: (Ord a) => Stree a -> (a,Stree a) splitTree (Fork xt y yt) = if empty xt then (y,yt) else (x, Fork wt y yt) where (x,wt) = splitTree xt 09.04.2019
Binary Heap Aufbau entspricht Binary Search Tree Definition in Haskell data (Ord a) => Htree a = Null | Fork a (Htree a) (Htree a) Für alle Kindelemente eines Knotens gilt >a 09.04.2019
Binary Heap Baum -> Liste Liste -> Baum flatten :: (Ord a) =>Htree a -> [a] flatten Null = [] flatten (Fork x xt yt) = x:merge (flatten xt) (flatten yt) merge:: (Ord a) =>[a] -> [a] -> [a] merge [] ys = ys merge xs [] = xs merge (x:xs) (y:ys) = if x<=y then x:merge xs (y:ys) else y:merge (x:xs) ys Liste -> Baum mkHeap :: (Ord a) => [a] -> Htree a mkHeap = heapify . mkHTree 09.04.2019
Binary Heap Liste -> Baum heapify :: (Ord a) => Htree a -> Htree a heapify Null = Null heapify (Fork x xt yt) = sift x (heapify xt) (heapify yt) sift :: (Ord a) => a -> Htree a -> Htree a -> Htree a sift x Null Null = Fork x Null Null sift x (Fork y a b) Null = if x <= y then Fork x (Fork y a b) Null else Fork y (sift x a b) Null sift x Null (Fork z c d) = if x <= z then Fork x Null (Fork z c d) else Fork z Null (sift x c d) sift x (Fork y a b) (Fork z c d) | x<=(y 'min' z) = Fork x (Fork y a b) (Fork z c d) | y<=(x 'min' z) = Fork y (sift x a b) (Fork z c d) | z<=(x 'min' y) = Fork z (Fork y a b) (sift x c d) insert :: (Ord a) => a -> Htree a -> Htree a insert x t = sift x Null t 09.04.2019
Rose Tree Knoten können beliebig viele Kinder haben Definition in Haskell data Rose a = Node a [Rose a] Blätter haben leere Listen von Kindern Binary Tree entspricht einem Rose Tree 2. Ordnung 09.04.2019
Rose Tree Berechnung der Eigenschaften size :: Rose a -> Int size (Node x xts) = 1 + sum (map size xts) height :: Rose a -> Int height (Node x xts) = 1 + maxlist (map height xts) where maxlist = foldl (max) 0 nodes :: Rose a -> Int nodes (Node x []) = 0 nodes (Node x xts) = 1 + sum(map nodes xts) 09.04.2019
Rose Tree fold-Funktion map-Funktion foldRose :: (a -> [b] -> b) -> Rose a -> b foldRose f (Node x xts) = f x (map (foldRose f) xts) map-Funktion mapRose :: (a -> b) -> Rose a -> Rose b mapRose f = foldRose (Node . f) 09.04.2019
Rose Tree Baum -> Liste Breadth-First Depth-First 09.04.2019
Rose Tree Baum -> Liste (breadth-first) level :: Rose a -> [a] level = concat . levels levels :: Rose a -> [[a]] levels (Node x xts) = [x]:combine (map levels xts) combine :: [[[a]]] -> [[a]] combine = foldr (zipWith2) [] zipWith2 :: [[a]] -> [[a]] -> [[a]] zipWith2 [] yss = yss zipWith2 xss [] = xss zipWith2 (xs:xss) (ys:yss) = (xs++ys):(zipWith2 xss yss) 09.04.2019
Rose Tree Baum -> Liste (depth-first) Eigenschaften der Funktionen flatten :: Rose a -> [a] flatten (Node x xts) = x:concat (map flatten xts) Eigenschaften der Funktionen breadth-first: Kann auf unendliche Bäume angewendet werden werden depth-first: Braucht deutlich weniger Speicherplatz 09.04.2019
Anwendungsbeispiel: Huffman Tree Dient der Datenkomprimierung Erzeugt aus einer Zeichenkette Bitcode variabler Länge Codierung der einzelnen Zeichen anhand ihrer Auftrittswahrscheinlichkeit Je größer die Auftrittswahrscheinlichkeit, desto kürzer die resultierende Bitfolge 09.04.2019
Anwendungsbeispiel: Huffman Tree Teilprobleme bei der Implementierung der Huffmancodierung Ermitteln der Auftrittshäufigkeiten Aufbau des Huffman Tree Kodierung Dekodierung 09.04.2019
Anwendungsbeispiel: Huffman Tree Ermitteln der Auftrittshäufigkeiten Aus einer Zeichenkette wird eine Liste aus den einzelnen Zeichen mit deren Auftrittshäufigkeiten ermittelt Alphabetisches Sortieren der gegebenen Zeichenkette Ermittlung der Auftrittshäufigkeiten Sortierung entsprechend der Auftrittshäufigkeiten sample :: [Char] -> [(Char,Int)] sample = sortby snd . collate . sortby id collate :: [Char] -> [(Char,Int)] collate [] = [] collate (x:xs) = (x,1+(length ys)):collate zs where (ys,zs) = span (==x) xs 09.04.2019
Anwendungsbeispiel: Huffman Tree Aufbau des Huffman Tree mkHuff :: [(Char,Int)] -> BTree Char mkHuff = unlabel . unwrap . until singleton combine . map mktip Die Tupel der Liste werden in Blätter umgewandelt Aus den jeweils ersten beiden Bäumen der List wird ein neuer Baum generiert Sein Gewicht entspricht der Summe der Gewichte der Teilbäume Der Erzeugte Baum wird entsprechend seines Gewichts in die Liste einsortiert Es werden solange Bäume zusammengefügt, bis nur noch einer Übrig ist Abschließend werden die Gewichte aus dem Baum entfernt 09.04.2019
Anwendungsbeispiel: Huffman Tree Kodierung Einfacher Ansatz: Ermitteln der Bitfolge direkt am Baum Für jedes Zeichen erneute Traversierung notwendig => Ineffizient Effizientere Lösung: Umwandlung des Baumes in einen CodeTable 09.04.2019
Anwendungsbeispiel: Huffman Tree Kodierung type CodeTable = [(Char,[Bit])] transform :: Btree Char -> CodeTable Baum wird einmal traversiert Zeichen in den Blättern und zugehörige Bitfolge werden in Tupeln gespeichert Resultierende Liste aus Tupeln ist entsprechend der Länge der Bitfolge sortiert 09.04.2019
Anwendungsbeispiel: Huffman Tree Kodierung encode :: Btree Char -> [Char] -> [Bit] encode t = concat . map (codelookup codetable) where codetable = transform t codelookup :: CodeTable -> Char -> [Bit] codelookup ((x,bs) : xbs) y = if x == y then bs else codelookup xbs y 09.04.2019
Anwendungsbeispiel: Huffman Tree Dekodierung decode :: BTree Char -> [Bit] -> [Char] decode t cs = if null cs then [] else decode1 t cs where decode1 (Leaf x) cs = x : decode t cs decode1 (Fork xt yt) (0:cs) = decode1 xt cs decode1 (Fork xt yt) (1:cs) = decode1 yt cs 09.04.2019