6 Baumstrukturen Formale Grundlagen der Informatik I Herbstsemester 2012 Robert Marti Vorlesung teilweise basierend auf Unterlagen von Prof. emer. Helmut Schauer Beispiel: Hierarchisches File System FGI 2012 06 Baumstrukturen 2 Beispiel: Entscheidungsbaum (Decision Tree) if Hair_color = 'Blonde' and Lotion_used = 'No' then Sunburn = 'Yes' FGI 2012 06 Baumstrukturen 3 Beispiel: Operatorbaum • Beispiel: (a + b) · c bzw. (a + b) * c * • Darstellung als Baum – Variablen sind Knoten – Operatoren sind ebenfalls Knoten, deren Unterbäume sind Operanden + c • Traversieren des Baums – preorder: * + a b c in der Sprache Lisp: (* (+ a b) c) – inorder: a b (a + b) * c – postorder: a b + c * z.B. HP Calculators (UPN bzw. RPN), Sprachen Forth, Postscript FGI 2012 06 Baumstrukturen 4 Beispiel: XML Dokument als Baum bibliography book title author Found… Abiteboul FGI 2012 book author author publisher year Hull Vianu Addison… 1995 06 Baumstrukturen <bibliography> <book> <title> Foundations of Databases </title> <author>Abiteboul</author> <author>Hull</author> <author>Vianu</author> <publisher> Addison Wesley </publisher> <year>1995</year> </book> <book> ... </book> </bibliography> 5 Beispiel: Beweis-Baum (Proof Tree) Δ := { has-part(system, monitor) , not-plugged-in(system) , defect(system) ← has-part(system, monitor) ∧ defect(monitor) , does-not-work(system) ← defect(system) , does-not-work(system) ← not-plugged-in(system) } goal := ← does-not-work(system) [1] [2] [3] [4] [5] ← does-not-work(system) Resolution mit [4] Resolution mit [5] ← defect(system) ← not-plugged-in(system) Resolution mit [3] Resolution mit [2] ← has-part(system, monitor) ∧ defect(monitor) Erfolg Resolution mit [1] ← defect(monitor) Fehlschlag FGI 2012 06 Baumstrukturen 6 Beispiel: Taxonomie von Geschäftsbegriffen sog. Lines of Business im Versicherungsbereich All Lines P&C Lines Property Casualty L&H Lines Special Lines Life Health 'Casualty' is a narrower term than 'P&C Lines' FGI 2012 06 Baumstrukturen 7 Definitionen (1) Ein Baum (tree) ist - entweder leer - oder er besteht aus einer Wurzel (root) mit einer beliebigen Anzahl n ≥ 0 von Teilbäumen (subtrees), von denen jeder wiederum ein Baum ist. Die Wurzel des Baumes sowie die Wurzeln seiner Teilbäume heissen Knoten (nodes oder auch vertices [= Plural von vertex]) des Baumes. Die Teilbäume sind mit der Wurzel durch Kanten (edges) verbunden. Wurzelknoten Kanten … FGI 2012 06 Baumstrukturen Teilbäume 8 Definitionen (2) Knoten ohne Teilbäume (bzw. Knoten, deren Teilbäume alle leer sind) heissen Blätter (leaves). Eine Folge von Knoten die durch Kanten miteinander verbunden sind, heisst Pfad (path). Zwischen zwei beliebigen Knoten eines Baumes gibt es genau einen Pfad. … … … … … … FGI 2012 06 Baumstrukturen 9 Geordneter Baum Knoten in einem Baum haben im allgemeinen • eine Etikette (label) bzw. einen Schlüssel (key) • und/oder einen Wert (value). In einem geordneten Baum (ordered tree) ist die Reihenfolge der Teilbäume jedes Knotens relevant. Dies kann eine explizite Ordnung sein oder aber eine Sortierreihenfolge, die vom Schlüssel oder vom Wert der Wurzelknoten der Teilbäume induziert wird. Bäume, die sich nur durch die Reihenfolge ihrer Teilbäume unterscheiden, werden als zueinander isomorph bezeichnet. FGI 2012 06 Baumstrukturen 10 Beispiel: Isomorphe Bäume FGI 2012 06 Baumstrukturen 11 Ordnung eines Baums Die maximale Anzahl von Teilbäumen eines Knotens entspricht der Ordnung (degree) eines Baumes. Die (exakte oder mittlere) Anzahl von Teilbäumen eines Knotens wird auch als fanout bezeichnet. Beispiel: Baum der Ordnung 3 Datenstruktur: Tree = value subtree1 subtree2 subtree3 FGI 2012 06 Baumstrukturen 12 Binärer Baum Ein binärer Baum (binary tree) ist ein Baum in dem jeder Knoten maximal zwei Teilbäume hat. Binäre Bäume haben die Ordnung 2. Ist der binäre Baum geordnet, so sprechen wir von linken und rechten Teilbäumen. Datenstruktur: Tree = value left FGI 2012 right 06 Baumstrukturen 13 Perfekter binärer Baum Ein binärer Baum heisst perfekt oder voll wenn für jeden Knoten gilt: Der linke und der rechte Teilbaum dieses Knotens besteht aus gleich vielen Knoten. In einem perfekten binären Baum ist jeder Knoten - entweder ein Blattknoten - oder er hat genau zwei nicht leere Teilbäume. FGI 2012 06 Baumstrukturen 14 Höhe eines Baums und Tiefe eines Knotens Die Höhe (height) eines Baumes ist die maximale Pfadlänge von der Wurzel zu den Blättern des Baumes. Bemerkung: Die Höhe wird bisweilen auch als Tiefe (depth) bezeichnet, siehe auch unten. Die Tiefe (depth) [auch Ebene (level)] eines Knotens x ist die Länge des Pfades dieses Knotens zur Wurzel … Baumhöhe: 3 Tiefe des Knotens: 2 … x … FGI 2012 06 Baumstrukturen 15 Höhe und totale Anzahl von Knoten in perfekten Bäumen Ein perfekter binärer Baum der Höhe h hat genau 2h Blätter. Für die totale Anzahl n von Knoten innerhalb eines solchen Baums gilt: n = 1 + 2 + … + 2h = xxxxx = 2h+1 − 1 bzw. h = log2(n + 1) − 1 Generalisierungen: Für perfekte Bäume mit Höhe h und Ordnung f (bzw. annäherungsweise für Bäume mit mittlerem fanout f , f ≥ 2) gilt: - Die Anzahl Blätter ist genau f h - n = 1 + f + … + f h = (f h+1 − 1) / (f − 1) ≤ 2⋅(f h+1 − 1) / f ≤ 2⋅f h - logf (n) ≤ h ≤ logf (n / 2) FGI 2012 06 Baumstrukturen 16 Beispiel: Perfekter binärer Baum n=7 h=2 FGI 2012 06 Baumstrukturen 17 Traversieren eines Baums: "in-order" Damit alle Knoten eines Baums bearbeitet werden können, muss der Baum traversiert werden (tree traversal). Pseudocode für das "in-order" Traversieren eines Baums procedure traverse(t: Tree); begin if not empty(t) then traverse(t.left); // rekursiver Aufruf: traversiere linken Teilbaum process(t.key); // bearbeite den "Inhalt" des Wurzelknotens // (z.B. Ausgabe auf Bildschirm) traverse(r.right); // rekursiver Aufruf: traversiere rechten Teilbaum end; end traverse; FGI 2012 06 Baumstrukturen 18 Traversieren eines Baums: "pre-order" Pre-Order: Verarbeite den "Inhalt" des Wurzelknotens zuerst. Pseudocode für das "pre-order" Traversieren eines Baums procedure preorder(t: Tree); begin if not empty(t) then process(t.key); // bearbeite den "Inhalt" des Wurzelknotens // (z.B. Ausgabe auf Bildschirm) preorder(t.left); // rekursiver Aufruf: traversiere linken Teilbaum preorder(r.right); // rekursiver Aufruf: traversiere rechten Teilbaum end; end preorder; FGI 2012 06 Baumstrukturen 19 Traversieren eines Baums: "post-order" Post-Order: Verarbeite den "Inhalt" des Wurzelknotens zuletzt. Pseudocode für das "post-order" Traversieren eines Baums procedure postorder(t: Tree); begin if not empty(t) then postorder(t.left); // rekursiver Aufruf: traversiere linken Teilbaum postorder(r.right); // rekursiver Aufruf: traversiere rechten Teilbaum process(t.key); // bearbeite den "Inhalt" des Wurzelknotens // (z.B. Ausgabe auf Bildschirm) end; end postorder; FGI 2012 06 Baumstrukturen 20 Beispiel: Binärer Baum (1) Beispiel: Arithmetischer Ausdruck (a+b)*c * c + a FGI 2012 pre-order: *+abc in-order: (a+b)*c post-order: ab+c* b 06 Baumstrukturen 21 Beispiel: Binärer Baum (2) Beispiel: Arithmetischer Ausdruck a+b*c + a pre-order: +a*bc in-order: a+b*c post-order: abc*+ FGI 2012 * b 06 Baumstrukturen c 22 Binärer Sortierbaum Ein binärer Sortierbaum ist ein geordneter binärer attributierter Baum für den beim in-order Traversieren alle Attribute gemäss ihrer Ordnungsrelation durchlaufen werden. Seien - x ein Knoten eines binären Sortierbaums T - x.key das Attribut des Knotens x sowie - x.left und x.right der linke respektive rechte Teilbaum des Knotens x, dann gilt (bei ansteigender Sortierteihenfolge) eines Sortierbaumes T: ∀ x: x ∈ T: (∀ y: y ∈ x.left: y.key ≤ x.key) ∧ (∀ y: y ∈ x.right: y.key ≥ x.key) Jeder Teilbaum eines Sortierbaums ist selbst ein Sortierbaum FGI 2012 06 Baumstrukturen 23 Beispiel: Binärer Baum als Sortierbaum Binärer Sortierbaum b a d in-order: abcde pre-order: badce post-order: acedb level-order: badce (zuerst Level 0 (= Wurzel), dann Knoten auf Level 1, … ) c FGI 2012 06 Baumstrukturen e 24 Traversieren eines Baums: ”level-order" Level-Order: Zuerst Level 0 (Wurzel), dann Level 1 Knoten, ... ) procedure traverseUntil(t: Tree; maxlevel: integer; level: integer); begin if not empty(t) then if level = maxlevel then process(t.key); else traverseUntil (t.left, maxlevel, level+1); traverseUntil (r.right, maxlevel, level+1); end; end traverseUntil; procedure levelOrder(t: Tree); // Dies ist eine Implementation namens „iterative deepening“ begin for level := 0 to depth(t) do traverseUntil(t, level, 0); end; end levelOrder; FGI 2012 06 Baumstrukturen 25 Warum sind Sortierbäume wichtig? Gegeben eine ungeordnete Liste mit n Datensätzen (records), z.B. Informationen über Personen. Um einen Datensatz mit einem bestimmten Namen zu finden, muss/müssen - im besten Fall 1 Datensatz (*) - im schlechtesten Fall n Datensätze angeschaut werden, (im Mittel n+1/2) Bei einem perfekten binären Baum sind es - im besten Fall 1 Datensatz (*) - im schlechtesten Fall h = log2(n + 1) − 1 Datensätze. (bei n = 1'000'000 sind dies noch 19 Datensätze) (*) Dies gilt nur, wenn die Namen eindeutig sind! FGI 2012 06 Baumstrukturen 26 Problem: Sortierbäume sind nicht immer balanciert ... Die Reihenfolge des Einfügens spielt eine Rolle! einzufügende Zahlen 1, 2, 3 resultierender Sortierbaum 1 2 3 FGI 2012 06 Baumstrukturen 27 Einfügen eines Schlüsselwerts in einen Baum Pseudocode für das Einfügen eines Schlüsselwerts k in einen Baum t procedure insert(k: KeyValue; var t: Tree); begin if not empty(t) then if k < t.key then insert(k, t.left); // rekursiver Aufruf: füge k in linken Teilbaum ein else if k > t.key then insert(k, right); // rekursiver Aufruf: füge k in rechtenTeilbaum ein end; else // der Baum (bzw. Teilbaum) ist leer t := new Tree; // erzeuge einen neuen Knoten t.key := k; t.left := nothing; t.right := nothing; end; end insert; FGI 2012 06 Baumstrukturen 28 Problem: Sortierbäume sind nicht immer balanciert ... Reihenfolge des Einfügens: 1, 2, 3 3, 2, 1 1 3 2 2 3 2, 1, 3 1 2, 3, 1 2 1 FGI 2012 2 3 1 06 Baumstrukturen 3 29 B Bäume B Bäume und ihre Varianten (B+ Baum) wurden 1972 von Rudolf Bayer und Ed McCreight zur Indizierung grosser Datenmengen auf Disk erfunden. B Bäume sind Mehrwegbäume, wobei B primär für Balanced steht (und nebenbei vielleicht für Boeing und/oder Rudolf Bayer) Eigenschaften eines B+ Baums - Die minimale und maximale Pfadelänge von der Wurzel zu einem Blatt unterscheidet sich höchstens um 1. - Jeder "innere Knoten" hat zwischen ⎡n/2⎤ und n Unterbäume. - Ein Blattknoten hat zwischen ⎡(n–1)/2⎤ und n–1 Werte Spezialfälle: Wenn die Wurzel kein Blattknoten ist, dann hat sie mindestens 2 Unterbäume. Wenn die Wurzel ein Blattknoten ist (und somt der einzige Knoten des Baums ist), kann sie zwischen 0 und (n–1) Werte haben. FGI 2012 06 Baumstrukturen 30 Beispiel eines B+-Baums FGI 2012 06 Baumstrukturen 31 Fanout in B-Bäumen • In Datenbanksystemen sind die Daten auf Disk in Blöcken von 8 kByte oder 16 kByte gespeichert. • Der Fanout f berechnet sich aus der Blockgrösse S, dem Platzbedarf für einen Indexwert V sowie dem Platzbedarf für einen Pointer auf ein Tupel (sog. TID) P: f = ⎣ (S−P) / (V+P) ⎦ Beispiele für 8kByte Seiten (ohne Header-Info ≈ 8000 Byte, 8-byte TID) ⎣ (8000−8) / (4+8) ⎦ = 666 für 4-Byte INTEGER ⎣ (8000−8) / (256+8) ⎦ = 30 für 256-Byte String • Worst-Case-Komplexität (Anzahl der Seitenzugriffe) für Suchen, Einfügen und Löschen in einem B-Baum mit insgesamt n Datensätzen: O(logf n). • Mittlere Speicherplatzauslastung bei zufälligem Einfügen: ln 2 ≈ 0.69. FGI 2012 06 Baumstrukturen 32