Binäre Suchbäume Mengen, Funktionalität, Binäre Suchbäume, Heaps, Treaps Mengen n Ziel: Aufrechterhalten einer Menge (hier: ganzer Zahlen) unter folgenden Operationen: Mengen n Ziel: Aufrechterhalten einer Menge (hier: ganzer Zahlen) unter folgenden Operationen: n n Einfügen eines Elements Löschen eines Elements Mengen n Ziel: Aufrechterhalten einer Menge (hier: ganzer Zahlen) unter folgenden Operationen: n n n Einfügen eines Elements Löschen eines Elements Suchen eines Elements Mengen n Ziel: Aufrechterhalten einer Menge (hier: ganzer Zahlen) unter folgenden Operationen: n n n n Einfügen eines Elements Löschen eines Elements Suchen eines Elements Anforderung: effizient auch bei grossen Mengen! Mengen: Anwendungen (I) n Telefonbuch (Menge von Namen mit zugehörigen Telefonnummern) n n n Einfügen: Neue Telefonanschlüsse Löschen: Aufgegebene Telefonanschlüsse Suchen: Telefonnummer einer Person Mengen: Anwendungen (II) n Nutzerverwaltung (Menge von Nutzern mit Passwörtern und/oder weiteren Informationen) n n n Einfügen: Neue Nutzer Löschen: Ex-Nutzer Suchen: Einloggen Mengen: Anwendungen (II) n Nutzerverwaltung (Menge von Nutzern mit Passwörtern und/oder weiteren Informationen) n n n n Einfügen: Neue Nutzer Löschen: Ex-Nutzer Suchen: Einloggen Effizienz: Keine Wartezeit beim Einloggen, auch bei Millionen von Nutzern. Mengen: Lösung mit Listen n Menge wird als Liste gespeichert. 0 1 6 5 8 9 7 3 Mengen: Lösung mit Listen n Menge wird als Liste gespeichert. n Einfügen: zum Beispiel vorne anfügen (effizient) 2 1 6 5 8 0 9 7 3 Mengen: Lösung mit Listen n Menge wird als Liste gespeichert. n Einfügen: zum Beispiel vorne anfügen (effizient) 2 1 6 5 8 0 9 7 3 Mengen: Lösung mit Listen n Menge wird als Liste gespeichert. n Löschen: Durchlaufen der Liste bis zum Element (oder bis zum Ende, falls nicht vorhanden), Zeiger umhängen. 2 1 6 5 8 0 9 7 3 Mengen: Lösung mit Listen n Menge wird als Liste gespeichert. n Suchen: Durchlaufen der Liste bis zum Element (oder bis zum Ende, falls nicht vorhanden). 2 1 6 5 8 0 9 7 3 Mengen: Lösung mit Listen n Falls die Menge n Elemente enthält, so ist der Aufwand fürs Suchen eines Elements im schlimmsten Fall proportional zu n. Mengen: Lösung mit Listen n n Falls die Menge n Elemente enthält, so ist der Aufwand fürs Suchen eines Elements im schlimmsten Fall proportional zu n. Facebook: Zeit zum Einloggen wäre proportional zur Anzahl der Nutzer. Mengen: Lösung mit Listen n Beispiel: Suche nach den letzten 100 Elementen in einer Liste von 10,000,000 Elementen Mengen: Lösung mit Listen n Beispiel: Suche nach den letzten 100 Elementen in einer Liste von 10,000,000 Elementen List l; for (int i=0; i<10000000; ++i) l.push_front(i); // ...and search for the 100 first ones for (int i=0; i<100; ++i) l.find(i); Mengen: Lösung mit Listen n Beispiel: Suche nach den letzten 100 Elementen in einer Liste von 10,000,000 Elementen List l; for (int i=0; i<10000000; ++i) l.push_front(i); // ...and search for the 100 first ones for (int i=0; i<100; ++i) 6.5 Sekunden l.find(i); Mengen: Lösung mit Listen n Beispiel: Suche nach den letzten 100 Elementen in einer Liste von 10,000,000 Elementen Facebook hat 1,000,000,000 List l; Nutzer, eine for (int i=0; i<10000000; ++i) Suche würde l.push_front(i); 6.5 Sekunden dauern! // ...and search for the 100 first ones for (int i=0; i<100; ++i) 6.5 Sekunden l.find(i); Mengen: Lösung mit Listen n n Beispiel: Suche nach den letzten 100 Elementen in einer Liste von 10,000,000 Elementen Finden eines Elements: const Node* List::find (int key) { for (const Node* p = head_; p != 0; p = p>get_next()) if (p->get_key() == key) return p; return 0; } Mengen: Lösung mit Binären Suchbäumen. n n Falls die Menge n Elemente enthält, so ist der Aufwand fürs Suchen eines Elements im schlimmsten Fall proportional zu log2 n. Facebook: Zeit zum Einloggen ist proportional zum Logarithmus der Anzahl der Nutzer. Mengen: Lösung mit Binären Suchbäumen. n n Falls die Menge n Elemente enthält, so ist der Aufwand fürs Suchen eines Elements im schlimmsten Fall proportional zu log2 n. Facebook: Zeit zum Einloggen ist proportional zum Logarithmus der Anzahl der Nutzer. log2(1,000,000,000) ≈ 30. Mengen: Lösung mit Binären Suchbäumen. n n Falls die Menge n Elemente enthält, so ist der Aufwand fürs Suchen eines Elements im schlimmsten Fall proportional zu log2 n. Auch Einfügen und Löschen geht in Zeit proportional to log2 n. Binärbäume, Definition und Terminologie n Ein binärer Baum ist entweder leer,... Binärbäume, Definition und Terminologie n n Ein binärer Baum ist entweder leer,... oder er besteht aus einem Knoten (Kreis) n mit einem Schlüssel (hier: ganze Zahl),... 3 Binärbäume, Definition und Terminologie n n Ein binärer Baum ist entweder leer,... oder er besteht aus einem Knoten (Kreis) mit einem Schlüssel (hier: ganze Zahl),... n und einem linken und rechten Teilbaum, die jeweils Binärbäume sind. n 3 Binärbäume, Definition und Terminologie n n Ein binärer Baum ist entweder leer,... oder er besteht aus einem Knoten (Kreis) mit einem Schlüssel (hier: ganze Zahl),... n und einem linken und rechten Teilbaum, die jeweils Binärbäume sind. n 3 Linker Teilbaum Wurzel des Baums Rechter Teilbaum Binäre Suchbäume n Ein Binärbaum heisst binärer Suchbaum, wenn er leer ist, oder wenn folgende Bedingungen gelten: Sowohl der linke als auch der rechte Teilbaum sind binäre Suchbäume. n Der Schlüssel der Wurzel ist n n n > alle Schlüssel im linken Teilbaum, und ≦ alle Schlüssel im rechten Teilbaum. Binäre Suchbäume: Beispiel 4 3 8 1 6 2 5 9 7 Binäre Suchbäume: Beispiel 4 3 8 1 6 2 5 9 7 Blätter des Baums Binäre Suchbäume: Suchen nach einem Schlüssel 5? 4 3 8 1 6 2 5 9 7 Binäre Suchbäume: Suchen nach einem Schlüssel 4 =5? 3 8 1 6 2 nein 5 9 7 Binäre Suchbäume: Suchen nach einem Schlüssel 4 >5? 3 ja 1 8 6 2 5 Nein, also muss die 5 rechts sein. 9 7 Binäre Suchbäume: Suchen nach einem Schlüssel 4 3 8 1 6 2 5 =5? nein 9 7 Binäre Suchbäume: Suchen nach einem Schlüssel 4 3 Ja, also muss die 5 links sein. 8 >5? nein 1 6 2 5 9 7 Binäre Suchbäume: Suchen nach einem Schlüssel 4 3 8 1 6 2 5 =5? 7 nein 9 Binäre Suchbäume: Suchen nach einem Schlüssel 4 3 1 8 Ja, also muss die 5 links sein. 2 5 6 >5? nein 7 9 Binäre Suchbäume: Suchen nach einem Schlüssel 4 3 8 1 6 2 5 =5? 9 7 Ja, Schlüssel gefunden! Binäre Suchbäume: Suchen nach einem Schlüssel 0? 4 3 8 1 0 müsste links von der 1 sein, Teilbaum ist aber leer ⇒ 0 nicht da. 6 2 5 9 7 Mengen: Lösung mit binären Suchbäumen n Speichere die Elemente der Menge als Schlüssel in einem binären Suchbaum! Mengen: Lösung mit binären Suchbäumen n n Speichere die Elemente der Menge als Schlüssel in einem binären Suchbaum! Suchzeit ist proportional zur Höhe des Baums (Länge des längsten Pfades von der Wurzel bis zu einem Blatt). Mengen: Lösung mit binären Suchbäumen 4 3 8 1 6 2 5 9 7 Höhe 3 Mengen: Lösung mit binären Suchbäumen n n n Speichere die Elemente der Menge als Schlüssel in einem binären Suchbaum! Suchzeit ist proportional zur Höhe des Baums (Länge des längsten Pfades von der Wurzel bis zu einem Blatt). Einfügen und Löschen von Elementen? Binäre Suchbäume: Einfügen n Neues Element suchen und als Blatt an der passenden Stelle anhängen! Binäre Suchbäume: Einfügen 0 einfügen 4 3 8 1 0 müsste links von der 1 sein, Teilbaum ist aber leer ⇒ neues Blatt 6 2 5 9 7 Binäre Suchbäume: Einfügen 0 einfügen 4 3 8 1 0 6 2 5 9 7 Binäre Suchbäume: Einfügen n n Neues Element suchen und als Blatt an der passenden Stelle anhängen! Auch die Einfügezeit ist proportional zur Höhe des Baums. Binäre Suchbäume: Löschen n Element suchen, seinen Knoten durch Rotationen zu einem Blatt machen, Blatt löschen! Binäre Suchbäume: Löschen n n Element suchen, seinen Knoten durch Rotationen zu einem Blatt machen, Blatt löschen! Rotation: lokale Operation, welche die Positionen von Knoten verändert, nicht jedoch die Suchbaumeigenschaften. Rotation eines Teilbaums s t B A B Rotation eines Teilbaums s t C A B A<t≦B<s≦C Rotation eines Teilbaums Rechtsrotation s t t s C A A B A<t≦B<s≦C B = C A<t≦B<s≦C Rotation eines Teilbaums Rechtsrotation s t Linksrotation t s C A A B A<t≦B<s≦C B = C A<t≦B<s≦C Binäre Suchbäume: Löschen 8 löschen 4 3 8 1 6 2 5 9 7 Binäre Suchbäume: Löschen 8 löschen 4 3 8 1 6 2 5 A C 7 9 B Rechtsrotation (Linksrotation wäre auch möglich) Binäre Suchbäume: Löschen 8 löschen 4 3 1 6 5 8 A B 2 C 7 9 Binäre Suchbäume: Löschen 8 löschen 4 3 1 6 5 B und C sind leere Bäume 8 A 2 Linksrotation (Rechtsrotation wäre auch möglich) 7 9 B C Binäre Suchbäume: Löschen 8 löschen 4 3 1 6 B und C sind leere Bäume 5 2 9 C 8 A B 7 Binäre Suchbäume: Löschen 8 löschen 4 3 1 6 A, B, C sind leere Bäume 5 9 8 C 2 Rechtsrotation (Linksrotation wäre nicht möglich) 7 A B Binäre Suchbäume: Löschen 8 löschen 4 3 1 6 A, B, C sind leere Bäume 5 9 7 2 A 8 B C Binäre Suchbäume: Löschen 8 löschen 4 3 1 6 5 9 7 2 delete 8 Binäre Suchbäume: Löschen n n n Element suchen, seinen Knoten durch Rotationen zu einem Blatt machen, Blatt löschen! Rotation: lokale Operation, welche die Positionen von Knoten verändert, nicht jedoch die Suchbaumeigenschaften. Auch die Löschzeit ist proportional zur Höhe des Baums (nicht mehr ganz so offensichtlich) Die Höhe eines binären Suchbaums... n bestimmt die Laufzeit des n n n Suchens, Einfügens, Löschens. Die Höhe eines binären Suchbaums... n bestimmt die Laufzeit des n n n n Suchens, Einfügens, Löschens. kann aber bereits bei einer ungünstigen Einfügereihenfolge sehr gross werden! Die Höhe eines binären Suchbaums... n bestimmt die Laufzeit des n n n n n Suchens, Einfügens, Löschens. kann aber bereits bei einer ungünstigen Einfügereihenfolge sehr gross werden! Laufzeit im schlimmsten Fall nicht besser als bei einer Liste! Die Höhe eines binären Beispiel: Einfügen in Suchbaums... sortierter Reihenfolge 1 Die Höhe eines binären Beispiel: Einfügen in Suchbaums... sortierter Reihenfolge 1 2 Die Höhe eines binären Beispiel: Einfügen in Suchbaums... sortierter Reihenfolge 1 2 3 Die Höhe eines binären Beispiel: Einfügen in Suchbaums... sortierter Reihenfolge 1 2 3 n Höhe = n-1, Baum sieht aus und verhält sich wie eine Liste. Abhilfe: Balancierung n Beim Einfügen und Löschen stets darauf achten, dass der Baum „balanciert“ ist, (d.h. keine grossen Höhenunterschiede zwischen linken und rechten Teilbäumen) Abhilfe: Balancierung n n Beim Einfügen und Löschen stets darauf achten, dass der Baum „balanciert“ ist, (d.h. keine grossen Höhenunterschiede zwischen linken und rechten Teilbäumen) Verschiedene Möglichkeiten (mehr oder weniger kompliziert): n AVL-Bäume, Rot-Schwarz-Bäume,... Abhilfe: Balancierung n n Beim Einfügen und Löschen stets darauf achten, dass der Baum „balanciert“ ist, (d.h. keine grossen Höhenunterschiede zwischen linken und rechten Teilbäumen) Verschiedene Möglichkeiten (mehr oder weniger kompliziert): n n AVL-Bäume, Rot-Schwarz-Bäume,... Hier: Treaps (randomisierte Suchbäume) Treap = Tree + Heap n Ein Binärbaum heisst Heap, wenn er leer ist, oder wenn folgende Bedingungen gelten: Sowohl der linke als auch der rechte Teilbaum sind Heaps. n Der Schlüssel der Wurzel ist n n das Maximum aller Schlüssel. Heap: Schlüssel heissen Prioritäten n Ein Binärbaum heisst Heap, wenn er leer ist, oder wenn folgende Bedingungen gelten: Sowohl der linke als auch der rechte Teilbaum sind Heaps. n Die Priorität der Wurzel ist n n das Maximum aller Prioritäten. Heap: Beispiel 9 7 8 4 6 3 2 5 1 Treaps n Ein Binärbaum heisst Treap, wenn jeder Knoten einen Schlüssel und eine Priorität hat, so dass folgende Eigenschaften gelten: Der Baum ist ein binärer Suchbaum bzgl. der Schlüssel. n Der Baum ist ein Heap bzgl. der Prioritäten. n Treap: Beispiel Schlüssel Prioritäten 4, 9 3, 7 8, 8 1, 4 6, 6 2, 3 5, 2 9, 5 7, 1 Treaps: Eindeutigkeit n Satz: Für n Knoten mit verschiedenen Schlüsseln und Prioritäten gibt es genau einen Treap mit diesen Knoten. Treaps: Eindeutigkeit n n Satz: Für n Knoten mit verschiedenen Schlüsseln und Prioritäten gibt es genau einen Treap mit diesen Knoten. Beweis: Die Wurzel ist der Knoten mit der höchsten Priorität; im linken Teilbaum sind alle Knoten mit kleineren und im rechten Teilbaum alle Knoten mit grösseren Schlüsseln. Mit Induktion sind die Teilbäume auch eindeutig. Treaps mit zufälligen Prioritäten n Wir benutzen einen Treap als binären Suchbaum. Treaps mit zufälligen Prioritäten n n Wir benutzen einen Treap als binären Suchbaum. Beim Einfügen eines neuen Schlüssels wird seine Priorität zufällig gewählt. Treaps mit zufälligen Prioritäten n n n Wir benutzen einen Treap als binären Suchbaum. Beim Einfügen eines neuen Schlüssels wird seine Priorität zufällig gewählt. Wie bei normalen binären Suchbäumen: neuer Knoten wird neues Blatt. Treaps mit zufälligen Prioritäten n n n n Wir benutzen einen Treap als binären Suchbaum. Beim Einfügen eines neuen Schlüssels wird seine Priorität zufällig gewählt. Wie bei normalen binären Suchbäumen: neuer Knoten wird neues Blatt. Zusätzlich muss die Treap-Eigenschaft wieder hergestellt werden! Treaps: Einfügen 4, 9 0 einfügen, mit zufälliger Priorität 7.5 3, 7 8, 8 1, 4 6, 6 2, 3 5, 2 9, 5 7, 1 Treaps: Einfügen 4, 9 0 einfügen, mit zufälliger Priorität 7.5 3, 7 8, 8 1, 4 0, 7.5 Neues Blatt 6, 6 2, 3 5, 2 9, 5 7, 1 Treaps: Einfügen 4, 9 0 einfügen, mit zufälliger Priorität 7.5 3, 7 8, 8 1, 4 6, 6 9, 5 Heap-Eigenschaft verletzt: 4 < 7.5 0, 7.5 2, 3 5, 2 7, 1 Treaps: Einfügen 4, 9 0 einfügen, mit zufälliger Priorität 7.5 3, 7 8, 8 1, 4 0, 7.5 6, 6 2, 3 5, 2 Rechtsrotation! 9, 5 7, 1 Treaps: Einfügen 4, 9 0 einfügen, mit zufälliger Priorität 7.5 3, 7 8, 8 0, 7.5 6, 6 9, 5 1, 4 2, 3 5, 2 7, 1 Treaps: Einfügen 4, 9 0 einfügen, mit zufälliger Priorität 7.5 3, 7 0, 7.5 8, 8 Heap-Eigenschaft verletzt: 7 < 7.5 6, 6 9, 5 1, 4 2, 3 5, 2 7, 1 Treaps: Einfügen 4, 9 0 einfügen, mit zufälliger Priorität 7.5 3, 7 8, 8 0, 7.5 6, 6 9, 5 1, 4 2, 3 5, 2 Rechtsrotation! 7, 1 Treaps: Einfügen 4, 9 0 einfügen, mit zufälliger Priorität 7.5 0, 7.5 8, 8 3, 7 6, 6 9, 5 1, 4 2, 3 5, 2 7, 1 Treaps: Einfügen 4, 9 0, 7.5 0 einfügen, mit zufälliger Priorität 7.5 Heap-Eigenschaft ok, wir haben wieder einen Treap! 3, 7 6, 6 9, 5 1, 4 2, 3 5, 2 8, 8 7, 1 Treaps: Löschen n Element suchen, seinen Knoten durch Rotationen zu einem Blatt machen, Blatt löschen! Treaps: Löschen n n Element suchen, seinen Knoten durch Rotationen zu einem Blatt machen, Blatt löschen! Stets so rotieren, dass der Knoten mit seinem Nachfolger höherer Priorität vertauscht wird. Das erhält die HeapEigenschaft. Treaps: Löschen n n n Element suchen, seinen Knoten durch Rotationen zu einem Blatt machen, Blatt löschen! Stets so rotieren, dass der Knoten mit seinem Nachfolger höherer Priorität vertauscht wird. Das erhält die HeapEigenschaft. Suchbaum-Eigenschaft gilt wieder nach Löschen des Blatts. Treaps: Laufzeit n Satz (Seidel, Aragon 1996): In einem Treap über n Knoten mit zufälligen Prioritäten ist der zeitliche Aufwand für eine Einfüge-, Lösch- oder Suchoperation im Erwartungswert proportional zu log2n. Treaps: Laufzeit n n Satz (Seidel, Aragon 1996): In einem Treap über n Knoten mit zufälligen Prioritäten ist der zeitliche Aufwand für eine Einfüge-, Lösch- oder Suchoperation im Erwartungswert proportional zu log2n. Mehr dazu in der nächsten Stunde. Mengen: Lösung mit Treaps n Zur Erinnerung: Suche nach den letzten 100 Elementen in einer Liste von 10,000,000 Elementen List l; for (int i=0; i<10000000; ++i) l.push_front(i); // ...and search for the 100 first ones for (int i=0; i<100; ++i) 6.5 Sekunden l.find(i); Mengen: Lösung mit Treaps n Neu: Suche nach den letzten 100 Elementen in einem Treap von 10,000,000 Elementen Treap t; for (int i=0; i<10000000; ++i) t.insert(i); // ...and search for the 100 first ones for (int i=0; i<100; ++i) 0.017 Sekunden t.find(i); Sortieren mit Treaps n Folgerung: Durch Einfügen einer Folge von n Zahlen in einen Treap mit zufälligen Prioritäten kann die Folge in Zeit proportional zu n log2n sortiert werden. Sortieren mit Treaps n n Folgerung: Durch Einfügen einer Folge von n Zahlen in einen Treap mit zufälligen Prioritäten kann die Folge in Zeit proportional zu n log2n sortiert werden. Gleicher optimaler Proportionalitätsfaktor wie Mergesort Sortieren mit Treaps n n n Folgerung: Durch Einfügen einer Folge von n Zahlen in einen Treap mit zufälligen Prioritäten kann die Folge in Zeit proportional zu n log2n sortiert werden. Gleicher optimaler Proportionalitätsfaktor wie Mergesort Das Treap-basierte Verfahren ist im wesentlichen äquivalent zu Quicksort. Treaps in C++ n Aehnlich wie bei Listen: Klasse TreapNode für die Knoten n Jeder TreapNode speichert ausser Schlüssel und Priorität zwei Zeiger auf TreapNodes (linkes und rechtes Kind = Wurzeln des linken und rechten Teilbaums) n Treaps in C++ n Aehnlich wie bei Listen: Klasse TreapNode für die Knoten n Jeder TreapNode speichert ausser Schlüssel und Priorität zwei Zeiger auf TreapNodes (linkes und rechtes Kind = Wurzeln des linken und rechten Teilbaums) n Klasse Treap; jeder Treap ist durch einen Zeiger auf den Wurzelknoten repräsentiert. n Die Klasse TreapNode class TreapNode ! {! public:! // constructor! TreapNode( int key, int priority, TreapNode* left = 0, TreapNode* right = 0);! ! // Getters! int get_key() const;! int get_priority() const;! const TreapNode* get_left() const;! const TreapNode* get_right() const;! !! private:! int key_;! double priority_;! TreapNode* left_;! TreapNode* right_; !! friend class Treap;! }; ! Die Klasse TreapNode class TreapNode ! {! public:! // constructor! TreapNode( int key, int priority, TreapNode* left = 0, TreapNode* right = 0);! ! // Getters! int get_key() const;! int get_priority() const;! const TreapNode* get_left() const;! const TreapNode* get_right() const;! !! private:! int key_;! double priority_;! Wie bei Facebook: Freunde dürfen TreapNode* left_;! auf private Daten und Methoden TreapNode* right_; !! (Mitgliedsfunktionen) zugreifen. friend class Treap;! }; ! Die Klasse Treap Die „Viererbande“ class Treap { public: // default constructor: // POST: *this is an empty tree Treap(); … Konstruktor // copy constructor // POST *this is a copy of other Treap(const Treap& other); CopyKonstruktor // assignment operator // Post: other was assigned to *this Treap& operator= (const Treap& other); Zuweisungsoperator // Destructor ~Treap(); Destruktor Die Klasse Treap Die „Viererbande“ + Wurzel class Treap { public: // default constructor: // POST: *this is an empty tree Treap(); Konstruktor // copy constructor // POST *this is a copy of other Treap(const Treap& other); CopyKonstruktor // assignment operator // Post: other was assigned to *this Treap& operator= (const Treap& other); Zuweisungsoperator // Destructor ~Treap(); private: TreapNode* root_; … Destruktor Zeiger auf die Wurzel (0: leerer Treap) Die Klasse Treap Einfügen void Treap::insert(const int key)! {! insert (root_, key, std::rand());! }! Die Klasse Treap Einfügen void Treap::insert(const int key)! {! insert (root_, key, std::rand());! }! private Hilfsfunktion Zufällige Priorität Die Klasse Treap Einfügen // PRE: current is a pointer in *this // POST: a new TreapNode with key and priority is inserted into the // subtree hanging off current void Treap::insert (TreapNode*& current, const int key, const int priority) { if (current == 0) current = new TreapNode (key, priority); else if (key < current->key_) { insert (current->left_, key, priority); if (priority > current->get_priority()) rotate_right (current); } else { insert (current->right_, key, priority); if (priority > current->get_priority()) rotate_left (current); } } Die Klasse Treap Einfügen // PRE: current is a pointer in *this // POST: a new TreapNode with key and priority is inserted into the // subtree hanging off current void Treap::insert (TreapNode*& current, const int key, const int priority) { current verweist auf if (current == 0) current = new TreapNode (key, priority); eine leere Blattposition. else if (key < current->key_) { insert (current->left_, key, priority); if (priority > current->get_priority()) current rotate_right (current); } else { insert (current->right_, key, priority); 9, 8, 8 if (priority > current->get_priority()) rotate_left (current); } } 10 Die Klasse Treap Einfügen // PRE: current is a pointer in *this // POST: a new TreapNode with key and priority is inserted into the // subtree hanging off current void Treap::insert (TreapNode*& current, const int key, const int priority) { current verweist auf if (current == 0) current = new TreapNode (key, priority); eine leere Blattposition. else if (key < current->key_) { insert (current->left_, key, priority); if (priority > current->get_priority()) current rotate_right (current); } else { insert (current->right_, key, priority); 9, 10 8, 8 9, 10 if (priority > current->get_priority()) rotate_left (current); } } Die Klasse Treap Einfügen // PRE: current is a pointer in *this // POST: a new TreapNode with key and priority is inserted into the // subtree hanging off current void Treap::insert (TreapNode*& current, const int key, const int priority) { current verweist auf if (current == 0) current = new TreapNode (key, priority); eine leere Blattposition. else if (key < current->key_) { insert (current->left_, key, priority); if (priority > current->get_priority()) current rotate_right (current); } else { insert (current->right_, key, priority); 9, 10 8, 8 9, 10 if (priority > current->get_priority()) rotate_left (current); } } Damit das klappt, muss current ein Alias des entsprechenden Zeigers im Baum sein, keine Kopie! Die Klasse Treap Einfügen // PRE: current is a pointer in *this // POST: a new TreapNode with key and priority is inserted into the // subtree hanging off current void Treap::insert (TreapNode*& current, const int key, const int priority) { current verweist auf if (current == 0) current = new TreapNode (key, priority); eine leere Blattposition. else if (key < current->key_) { insert (current->left_, key, priority); if (priority > current->get_priority()) current rotate_right (current); } else { insert (current->right_, key, priority); 9, 10 8, 8 9, 10 if (priority > current->get_priority()) rotate_left (current); } } Heap-Eigenschaft ist noch verletzt; das wird „weiter oben“ in der Rekursion repariert. Die Klasse Treap Einfügen // PRE: current is a pointer in *this // POST: a new TreapNode with key and priority is inserted into the // subtree hanging off current void Treap::insert (TreapNode*& current, const int key, const int priority) { current verweist auf if (current == 0) current = new TreapNode (key, priority); einen Knoten. else if (key < current->key_) { current insert (current->left_, key, priority); if (priority > current->get_priority()) rotate_right (current); } else { insert (current->right_, key, priority); 9, 9 10 8 8, 8 if (priority > current->get_priority()) rotate_left (current); } } Die Klasse Treap Einfügen // PRE: current is a pointer in *this // POST: a new TreapNode with key and priority is inserted into the // subtree hanging off current void Treap::insert (TreapNode*& current, const int key, const int priority) { current verweist auf if (current == 0) current = new TreapNode (key, priority); einen Knoten. else if (key < current->key_) { current insert (current->left_, key, priority); if (priority > current->get_priority()) rotate_right (current); } else { insert (current->right_, key, priority); 9, 10 8, 8 if (priority > current->get_priority()) rotate_left (current); } } A 9, 10 Die Klasse Treap Einfügen // PRE: current is a pointer in *this // POST: a new TreapNode with key and priority is inserted into the // subtree hanging off current void Treap::insert (TreapNode*& current, const int key, const int priority) { current verweist auf if (current == 0) current = new TreapNode (key, priority); einen Knoten. else if (key < current->key_) { current insert (current->left_, key, priority); if (priority > current->get_priority()) rotate_right (current); } else { insert (current->right_, key, priority); 9, 10 8, 8 10 8 if (priority > current->get_priority()) rotate_left (current); } } A 9, 10 Die Klasse Treap Einfügen // PRE: current is a pointer in *this // POST: a new TreapNode with key and priority is inserted into the // subtree hanging off current void Treap::insert (TreapNode*& current, const int key, const int priority) { current verweist auf if (current == 0) current = new TreapNode (key, priority); einen Knoten. else if (key < current->key_) { current insert (current->left_, key, priority); if (priority > current->get_priority()) rotate_right (current); } else { insert (current->right_, key, priority); 9, 10 8, 8 if (priority > current->get_priority()) rotate_left (current); } } 9, 10 Die Klasse Treap Einfügen // PRE: current is a pointer in *this // POST: a new TreapNode with key and priority is inserted into the // subtree hanging off current void Treap::insert (TreapNode*& current, const int key, const int priority) { current verweist auf if (current == 0) current = new TreapNode (key, priority); einen Knoten. else if (key < current->key_) { current insert (current->left_, key, priority); if (priority > current->get_priority()) rotate_right (current); } else { insert (current->right_, key, priority); 9, 10 9, 10 if (priority > current->get_priority()) rotate_left (current); } } A 8, 8 Die Klasse Treap Einfügen // PRE: current is a pointer in *this // POST: a new TreapNode with key and priority is inserted into the // subtree hanging off current void Treap::insert (TreapNode*& current, const int key, const int priority) { current verweist auf if (current == 0) current = new TreapNode (key, priority); einen Knoten. else if (key < current->key_) { current insert (current->left_, key, priority); if (priority > current->get_priority()) rotate_right (current); } else { insert (current->right_, key, priority); 9, 10 9, 10 if (priority > current->get_priority()) rotate_left (current); } } A 8, 8 Fertig!