Abstrakte Datentypen II Prof. Dr. Markus Gross Informatik I für D-MAVT (FS 2014) Bäume Binäre Bäume Binäre Suchbäume Bäume Bäume sind verallgemeinerte Listenstrukturen: Ein Element (node) hat eine endliche, begrenzte Anzahl von Nachfolgern Bäume sind eine Struktur zur Speicherung von Schlüsseln Bäume bestehen aus einer Menge von Knoten, die hierarchisch organisiert sind 2 Bäume Jeder Knoten ausser dem Wurzelknoten (root) hat genau einen Vorgängerknoten (parent) Eine Kante drückt die Beziehung zwischen unmittelbarem Vorgänger und Nachfolger aus Der Grad eines Knoten ist die Zahl seiner unmittelbarer Nachfolger Ein Blattknoten (leaf) ist ein Knoten ohne Nachfolger, also mit Grad 0. Höhe eines Baumes: Maximaler Abstand (Anzahl Kanten) eines Blattes von der Wurzel 3 Bäume root parent Knoten mit Grad 3 Höhe des Baums = 2 leaves 4 Binärbäume Spezialfall: Grad = 2, das heisst, jeder Knoten hat maximal 2 Nachfolger Vollständiger Binärbaum: Alle Blätter haben die gleiche Tiefe 5 Binäre Suchbäume Schlüssel sind geordnet gespeichert Für jeden Knoten p gilt: Schlüssel im linken Teilbaum von p sind kleiner als der Schlüssel von p Schlüssel im rechten Teilbaum von p sind grösser als der Schlüssel von p 27 10 3 32 12 28 6 34 Binäre Suchbäume: Implementierung Implementierung mit einem Array: Knoten werden ebenenweise eingefüllt Positionen von Vorgängern und Nachfolgern müssen berechnet werden 27 10 3 32 12 28 27 10 32 34 7 3 12 28 34 Binäre Suchbäume: Implementierung i - 1 2 parent(i) = leftson(i) = 2*i + 1 rightson(i) = 2*i + 2 Parent von 12: (4-1)/2 = 1.5 -> 1 Linker Sohn von 10: 2*1 + 1 = 3 Rechter Sohn von 10: 2*1+2 = 4 27 10 32 27 10 32 0 3 12 28 34 8 1 2 3 12 28 34 3 4 5 6 Binäre Suchbäume: Implementierung Implementierung durch Pointer: Ähnlich wie verkettete Liste, jedoch hat nun jeder Knoten zwei Nachfolger struct element { int value; // The value of the element struct element *left; // Pointer to the left son Struct element *right; // Pointer to the right son }; typedef struct element Node; Node *root = NULL; //Pointer to root element 9 Binäre Suchbäume - Operationen Durchlaufen aller Knoten Wörterbuchoperationen: Suchen Einfügen Entfernen 10 Durchlaufordnungen I Hauptreihenfolge (preorder): Wurzel, linker Teilbaum, rechter Teilbaum 27, 10, 3, 12, 32, 28, 34 27 10 3 32 12 28 11 34 Durchlaufordnungen II Nebenreihenfolge (postorder): linker Teilbaum, rechter Teilbaum, Wurzel 3, 12, 10, 28, 34, 32, 27 27 10 3 32 12 28 12 34 Durchlaufordnungen II Symmetrische Reihenfolge (inorder): linker Teilbaum, Wurzel, rechter Teilbaum 3, 10, 12, 27, 28, 32, 34 27 10 3 32 12 28 13 34 Beispiel: Symmetrische Reihenfolge #include <iostream> using namespace std; Deklaration eines Knotens struct element { int value; // The value of the element struct element *left; // Pointer to the left son struct element *right; // Pointer to the right son }; typedef struct element Node; Node *root = NULL; //Pointer to root element 14 Beispiel: Symmetrische Reihenfolge //Traverse a binary tree in symmetric order void traverse(Node *p) Rekursive Traversierung { if(p != NULL) { //Leaf reached? traverse(p->left); //traverse left sub-tree cout << p->value << " "; //print root traverse(p->right); //traverse right sub-tree } } 15 Binärer Suchbaum: Suchen Suche durch Vergleichen von Schlüsseln Start bei der Wurzel Bespiel: Suche nach Schlüssel 29 27 10 3 32 12 28 16 34 Binärer Suchbaum: Suchen Suche durch Vergleichen von Schlüsseln Start bei der Wurzel Bespiel: Suche nach Schlüssel 29 27 29 > 27 10 3 32 12 28 17 34 Binärer Suchbaum: Suchen Suche durch Vergleichen von Schlüsseln Start bei der Wurzel Bespiel: Suche nach Schlüssel 29 27 29 > 27 10 3 32 12 28 18 29 < 32 34 Binärer Suchbaum: Suchen Suche durch Vergleichen von Schlüsseln Start bei der Wurzel, kann rekursiv oder iterativ implementiert werden Bespiel: Suche nach Schlüssel 29 29 > 27 27 10 3 32 12 29 > 28 28 Blatt erreicht 19 29 < 32 34 Binärer Suchbaum: Einfügen 4 < 27 4 < 10 3 null 10 4>3 null 27 32 12 null 28 null null 20 34 null null null Binärer Suchbaum: Einfügen 4 < 27 4 < 10 3 10 4>3 null null 27 32 12 null 28 null null 4 21 34 null null null Binärer Suchbaum: Einfügen Höhe des Baumes ist abhängig von der Reihenfolge, in der die Schlüssel eingefügt werden Beispiel: 15, 39, 3, 27, 1, 14, 42 15 3 1 39 14 27 22 42 Binärer Suchbaum: Einfügen Vollständiger Binärbaum: Höhe = log2(n) Aufwand beim Suchen: Best case: 1 Worst case: log2(n) 15 3 1 39 14 27 h=2 42 23 Binärer Suchbaum: Einfügen Iteratives Einfügen kann zu einem entarteten Baum führen (abhängig von der Reihenfolge der Schlüssel) Beispiel: 1, 3, 14, 15, 27, 39, 42 1 3 14 15 27 39 42 24 Binärer Suchbaum: Einfügen Lineare Struktur: Höhe = n-1 Aufwand beim Suchen: Best case: 1 Worst case: n-1 1 3 14 h=6 15 27 39 42 25 Binärer Suchbaum: Entfernen Fall 1: Der zu entfernende Knoten p hat keine Nachfolger 27 10 32 3 2 12 8 11 29 21 28 26 38 31 34 41 Binärer Suchbaum: Entfernen Fall 2: Der zu entfernende Knoten p hat Nachfolger Ersetze p durch Nachfolger q mit kleinstem Schlüssel, der grösser als p ist 27 10 p 3 2 32 12 8 11 29 21 28 27 38 31 34 41 Binärer Suchbaum: Entfernen q ist der Knoten mit kleinstem Schlüssel im rechten Teilbaum von p Suche nach q: Einmal nach rechts “abbiegen”, dann immer nach links, bis Blatt erreicht 27 10 p 3 2 32 12 8 11 q 29 21 28 28 38 31 34 41