Teil 1: Suchen • • • • • Problemstellung Elementare Suchverfahren Hashverfahren Binäre Suchbäume Ausgeglichene Bäume – AVL-Bäume – Splay-Bäume • B-Bäume • Digitale Suchbäume • Heaps M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-1 Definition von AVL-Bäumen Ziel Ausgeglichene Bäume: Suchbäume mit einer maximalen Höhe von O(log n). Damit könnten alle Dictionary-Operationen in O(log n) ausgeführt werden. Definition AVL-Baum Ein binärer Suchbaum heißt AVL-Baum oder (höhen-)balancierter Baum, falls sich für jeden Knoten k die Höhen der beiden Teilbäume um höchstens 1 unterscheiden. Die Abkürzung AVL geht zurück auf Adelson-Velskij und Landis. Ein AVL-Baum hat eine maximale Höhe von etwa 1.5 log2n. [Ottmann u. Widmayer]. Beispiel für AVL-Baum: 5 10 3 10 3 -1 -2 2 5 12 1 +1 7 0 -1 1 0 0 M.O.Franz; Oktober 2007 11 0 0 2 12 0 0 +2 0 3 0 6 Beispiel für Nicht-AVL-Baum 15 0 0 7 1 Höhe des Teilbaums Höhenunterschied = Höhe rechter Teilbaum Höhe linker Teilbaum +1 8 0 0 Algorithmen und Datenstrukturen - Suchen (Beachte: Höhe eines leeren Teilbaums ist -1.) 1-2 Rotationen (1) Zentrale Eigenschaft von AVL-Bäumen: Ein unbalancierter Baum, der einen Höhenunterschied von -2 (linkslastiger Baum) oder +2 (rechtslastiger Baum) hat und dessen Teilbäume ausbalanciert sind, lassen sich durch eine einfache Rotationsoperation ausbalancieren. Fall A: Baum ist linkslastig, d.h. Höhenunterschied = -2 Unterfall A1: linker Teilbaum hat Höhenunterschied -1 oder 0: q p -2 q h-1 h+1 -1 od. 0 A B M.O.Franz; Oktober 2007 h p h od. h+1 A C h od. h-1 h 1 od. 0 Rotate Right Teilbäume A, B, und C sind ausbalanciert und können auch leer sein. Algorithmen und Datenstrukturen - Suchen h od. h-1 B h-1 C 1-3 Rotationen (2) Fall A: Baum ist linkslastig, d.h. Höhenunterschied = -2 Unterfall A2: linker Teilbaum hat Höhenunterschied +1: 2. p 1. h+1 -2 q h+1 h-1 +1 Rotate Left Right r 0 q D h-1 r h h-1 od. h-2 A B M.O.Franz; Oktober 2007 0 od.-1 h-1 h-2 od. h-1 C h A Algorithmen und Datenstrukturen - Suchen p 0 od.1 h-1 od. h-2 B h h-1 od. h-2 C h-1 D 1-4 Rotationen (2b) 2. p 1. p -2 q h+1 h+1 h-1 +1 D h-1 r B h-1 r h -1 od.-2 q 0 od.-1 h-1 h-2 od. h-1 C B A C D h-2 od. h-1 h h-1 od. h-2 A Rotate Left -2 h-1 od. h-2 Rotate Right h+1 r 0 q h 0 od.-1 h-1 A M.O.Franz; Oktober 2007 p 0 od.1 h-1 od. h-2 B Algorithmen und Datenstrukturen - Suchen h h-1 od. h-2 C h-1 D 1-5 Rotationen (3) Fall B: Baum ist rechtslastig, d.h. Höhenunterschied = +2 Unterfall B1: rechter Teilbaum hat Höhenunterschied 0 oder +1: q p +2 h-1 q h+1 p h od. h-1 B h od. h+1 0 od. +1 0 od. +1 A M.O.Franz; Oktober 2007 0 od. -1 Rotate Left h-1 h C A Algorithmen und Datenstrukturen - Suchen h C h od. h-1 B 1-6 Rotationen (4) Fall B: Baum ist rechtslastig, d.h. Höhenunterschied = +2 Unterfall B2: rechter Teilbaum hat Höhenunterschied -1: 2. p +2 h-1 h+1 Rotate Right Left 1. q r 0 -1 A r p h h-2 od. h-1 B M.O.Franz; Oktober 2007 h q h h-1 h-1 od. h-2 C D A Algorithmen und Datenstrukturen - Suchen B C D 1-7 Einfügen und Löschen in AVL-Bäumen Idee für Algorithmus: 1) Füge ein bzw. lösche wie bei binären Suchbäumen. 2) Gehe dann von der Einfügestelle bzw. Löschstelle bis zur Wurzel und balanciere falls notwendig mit einer Rotationsoperation lokal aus. Bemerkungen: • Da der Baum vor dem Einfügen bzw. Löschen ausbalanciert war, haben alle Teilbäume einen Höhenunterschied von -1, 0 oder +1. Damit können nach dem Schritt 1) nur die Fälle A1, A2, B1 oder B2 auftreten. • Es läßt sich zeigen, dass beim Schritt 2) maximal eine Rotationsoperation notwendig ist. Beweisskizze: für jeden der Fälle A1, A2, B1 und B2 zeigt man, dass der Teilbaum nach dem Anwenden der entsprechenden Rotationsoperation die gleiche Höhe besitzt wie vor dem Einfügen bzw. Löschen (Schritt 1). Damit können weiter oben im Baum keine weiteren unbalancierten Stellen entstehen. M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-8 Einfügen in AVL-Bäumen (1) Beispiel: 2 Gehe vom Knoten 5 in Richtung Wurzel bis zum ersten unbalancierten Teilbaum. 2 Füge 5 ein 1 3 1 3 4 4 5 2 1 2 Rotate Left (Fall B1) 3 1 4 +2 4 3 5 +1 5 0 M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-9 Einfügen in AVL-Bäumen (2) Beispiel: 4 4 2 2 6 Gehe bis zum ersten unbalancierten Teilbaum. 6 Füge 13 ein 3 1 5 7 3 1 14 5 14 7 15 15 13 4 4 2. 2 6 +2 1. 1 3 5 2 1 14 7 Rotate Right Left (Fall B2) 15 7 3 6 5 14 13 15 13 M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-10 Algorithmen (1) Datenstruktur Wie bei binären Suchbäumen. Zusätzlich wird für jeden Knoten im Baum noch die Höhe des entsprechenden Teilbaums abgespeichert. Algorithmen struct Node { int height; KeyType key; ValueType value; Node* left; // linkes Kind Node* right; // rechtes Kind }; Erweitere insert-Operation für binäre Suchbäume um Balancieroperation. (Die remove-Operation wird analog erweitert. Die search-Operation bleibt unverändert.) bool insertR(KeyType k, ValueType v, Node*& p) { bool ret; if (p == 0) { Ein Blatt hat p = new Node; die Höhe 0 p->key = k; p->value = v; p->height = 0; ret = true; } else if (k < p->key) Knoten wurde eingefügt: ret = insertR(k,v,p->left); daher Höhe aktualisieren else if (k > p->key) und ausbalancieren, falls ret = insertR(k,v,p->right); notwendig. else // k bereits vorhanden ret = false; Die blauen Anweisungen wurden if (ret) eingefügt, damit die Balancieroperation balance(p); nach rekursivem Aufruf und vor return ret; Verlassen der Funktion durchgeführt } werden kann. M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-11 Algorithmen (2) void balance(Node*& p) { if (p == 0) return; // Höhe aktualisieren: p->height = max(getHeight(p->left), getHeight(p->right)) + 1; // Balanciere aus, da Baum linkslastig: if (getBalance(p) == -2) { if (getBalance(p->left) <= 0) // d.h. == -1 od. 0 Fall A1 rotateRight(p); Fall A2 else // getBalance(p->left) == +1 rotateLeftRight(p); } // Balanciere aus, da Baum rechtslastig: else if (getBalance(p) == +2) { if (getBalance(p->right) >= 0) // d.h. == 0 od. +1 Fall B1 rotateLeft(p); Fall B2 else // getBalance(p->left) == -1 rotateRightLeft(p); } Höhe eines Baums. Ein leerer Baum hat die Höhe -1. int getHeight(const Node* p) { if (p == 0) return -1; else return p->height; } Höhenunterschied zwischen linken und rechten Unterbaum. int getBalance(const Node* p) { if (p==0) return 0; else return getHeight(p->right) - getHeight(p->left); } M.O.Franz; Oktober 2007 Bei einem leeren Baum, wird der Höhenunterschied als 0 definiert. Algorithmen und Datenstrukturen - Suchen 1-12 Algorithmen (3) void rotateRight (Node*& p) // Es muss p->left != 0 sein! Sonst könnte der Baum gar nicht // unbalanciert sein... { Node* q = p->left; p->left = q->right; q->right = p; p->height = max(getHeight(p->left), getHeight(p->right)) + 1; q->height = max(getHeight(q->left), getHeight(q->right)) + 1; p = q; } Rotate Right p q q p C A M.O.Franz; Oktober 2007 A B B Algorithmen und Datenstrukturen - Suchen C 1-13 Algorithmen (4) void rotateLeft (Node*& p) { // analog zu rotateRight; } p 1. -2 h+1 q void rotateLeftRight (Node*& p) // Es muss p->left != 0 sein! { rotateLeft(p->left); rotateRight(p); } h-1 +1 D h-1 h r h-1 od. h-2 A B void rotateRightLeft (Node*& p) // Es muss p->right != 0 sein! { rotateRight(p->right); rotateLeft(p); } C 2. p h+1 h q 0 od. h-1 -1 A M.O.Franz; Oktober 2007 h-2 od. h-1 -2 h-1 r -1 od. h-2 od. h-1 -2 D C B Algorithmen und Datenstrukturen - Suchen h-1 od. h-2 1-14 Teil 1: Suchen • • • • • Problemstellung Elementare Suchverfahren Hashverfahren Binäre Suchbäume Ausgeglichene Bäume – AVL-Bäume – Splay-Bäume • • • B-Bäume Digitale Suchbäume Heaps M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-15 Splay-Bäume • Splay-Bäume sind selbstanordnende Bäume. • Ziel: automatische Anpassung an Zugriffshäufigkeiten ohne explizite Speicherung von Balance-Information oder Häufigkeiten • Sind die Zugriffshäufigkeiten fest und vorher bekannt, so lassen sich optimale Suchbäume konstruieren, die die Suchkosten minimieren (s. Ottmann & Widmayer, 5.7) • Hier: Zugriffshäufigkeiten unbekannt oder variabel. • Grundidee: Move-to-root-Strategie - nach jedem Zugriff wird ein Knoten durch Rotationen in Richtung der Wurzel bewegt. • Splay: engl. verbreitern - Baum wird in die Breite angeordnet. M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-16 Eine einfache Idee (die nicht funktioniert) - 1 Jeder Knoten auf dem Zugangspfad vertauscht in einer Rotation die Position mit seinem Vorfahren. Beispiel: Zugriff auf k1 [Weiss, 1999] M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-17 Eine einfache Idee (die nicht funktioniert) - 2 Rotation k1 <-> k2 [Weiss, 1999] M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-18 Eine einfache Idee (die nicht funktioniert) - 3 Rotation k1 <-> k3 [Weiss, 1999] M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-19 Eine einfache Idee (die nicht funktioniert) - 4 Rotation k1 <-> k4 und k1 <-> k5 [Weiss, 1999] M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-20 Eine einfache Idee (die nicht funktioniert) - 5 Durch die Rotationen wird der Knoten nach dem Zugriff bis an die Wurzel transportiert. nächster Zugriff ist extrem schnell. Aber: Ein anderer Knoten (k3) wurde dafür fast bis unten gedrückt. Im Extremfall (z.B. bei einem Baum aus linken Kindern) wird die Struktur nicht wesentlich verbessert bzw. ergeben sich repetitive Folgen von Baumzuständen => O(MN) bei M Zugriffen. => Baum muß so umstrukturiert werden, das er möglichst „breit“ wird (splaying). M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-21 Splaying-Strategie 2 Regeln (+ 2 Spiegelbilder): „Zick-Zack“ => Doppelte Rotation wie im AVL-Baum „Zick-Zick“ M.O.Franz; Oktober 2007 [Weiss, 1999] Algorithmen und Datenstrukturen - Suchen 1-22 Splaying: Beispiel (1) [Weiss, 1999] „Zick-Zack“ M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-23 Splaying: Beispiel (2) [Weiss, 1999] „Zick-Zick“ M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-24 Verbreiterte Baumstruktur durch Splaying Splaying bewegt nicht nur die Knoten nach einem Zugriff an die Wurzel, sondern halbiert bei unbalancierten Bäumen oft die Tiefe der meisten Knoten auf dem Zugangspfad. [Weiss, 1999] M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-25 Amortisierte Worst-Case-Analyse Amortisierte Analyse: statt der Laufzeit einer einzigen Operation wird stattdessen die Laufzeit per Operation in einer Folge von M Operationen abgeschätzt. Bei einer Worst-Case-Laufzeit von O(M f(N)) ist die amortisierte Laufzeit O(f(N)) pro Operation. Man kann zeigen (s. Ottmann & Widmayer, 5.4.2): Splay-Bäume haben eine amortisierte Laufzeit von O(log N), egal welche Sequenz von Operationen gewählt wird. D.h. obwohl einzelne Operationen O(N) brauchen können, ist garantiert, daß die nachfolgenden Operationen um so kürzer sind, so daß sich bei hinreichend großen M insgesamt O(log N) ergeben. M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-26 Beispiel für Worst-Case (1) Splaying an Knoten 1 an einem Baum aus linken Kindern [Weiss, 1999] M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-27 Beispiel für Worst-Case (2) nach Splaying an Knoten 2 [Weiss, 1999] M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-28 Beispiel für Worst-Case (3) nach Splaying an Knoten 3 und 4 nach Splaying an Knoten 5 und 6 M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen [Weiss, 1999] 1-29 Beispiel für Worst-Case (4) nach Splaying an Knoten 7 und 8 [Weiss, 1999] M.O.Franz; Oktober 2007 Algorithmen und Datenstrukturen - Suchen 1-30