Binäre Suchbäume

Werbung
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.
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!
Herunterladen