Programmieren - Nichtlineare Datenstrukturen - fbi.h

Werbung
FB Informatik
Prof. Dr. R.Nitsch
Programmieren - Nichtlineare Datenstrukturen
Reiner Nitsch
 [email protected]
Nichtlineare Dynamische Datenstrukturen - Motivation
Operation
Suchen
Einfügen
Löschen
Auswählen
Sort. Array
O(log N)
O(N)
O(N)
O(1)
Sortierte physikalische Sequenzen (z.B.
C-Array, vector, deque, …) sind schnell
beim Auswählen (k-tes Element z.B. über
Index) bzw. Suchen (binäre Suche nach
bestimmtem Wert) aber langsam beim
Einfügen bzw. Löschen.
20.01.2012
Sort. Liste
O(N)
O(1)
O(1)
O(N)
FB Informatik
Prof. Dr. R.Nitsch
Bäume
O(log N)
O(1)
O(1)
O(log N)
Bei den logischen
Sequenzen (z.B.
sortierte Liste) sind
die Verhältnisse
genau umgekehrt!
Nichtlineare Datenstruktur Baum
Gesucht: Datenstruktur, die
die Vorteile von Liste und
Array vereint, also schnelles
Suchen, Einfügen und Löschen!
Lösung:
Bäume (Trees)!
2
Datenstruktur Baum - Terminologie und Definitionen
FB Informatik
Prof. Dr. R.Nitsch
Bäume als wichtige Teilklasse von Graphen:
Ein Baum ist ein einfacher, azyklischer,
zusammenhängender Graph mit ungerichteten Kanten
bei n Knoten hat er genau n-1 Kanten
Es gibt genau einen Pfad, der 2 Knoten verbindet
Knoten
Kante
Orientierter Baum (Wurzelbaum)
(ungerichteter) Baum
Es gibt einen ausgezeichneten Knoten, den man Wurzel
nennt
Die Wurzel bestimmt implizit die Orientierung der
Kanten (alle zur Wurzel hin oder von der Wurzel weg
gerichtet)
d
Wurzel (root)
Beispiel rechts:
d ist die Wurzel
d ist Elternknoten (Vorgänger) von b, k und e
b ist Kind (Nachfolger) von d
a
b, k und e haben denselben Elternknoten und sind daher
Geschwister
k
b
e
c
g
f
20.01.2012
Nichtlineare Datenstruktur Baum
h
3
Datenstruktur Baum - Terminologie und Definitionen
Der Grad eines Knotens (die Ordnung)
ist durch die Anzahl seiner Kinder
bestimmt.
Knoten ohne Kinder (Grad 0) heißen
Blatt. (a,c,k,f,h) Alle anderen Knoten
heißen innere Knoten (b,d,e,g)
Jeder Knoten mit Ausnahme der Wurzel
hat genau einen Elternknoten.
Der Grad (die Ordnung) eines Baumes
ergibt sich aus dem maximalen Grad
aller Knoten (manchmal auch auf
Englisch "fan-out" genannt)
Die Nachfahren eines Knotens v sind
alle Nachfolger und Nachfolger von
Nachfolgern usw.
20.01.2012
FB Informatik
Prof. Dr. R.Nitsch
Grad=3
d
Wurzel (root)
Grad=1
k
b
a
Nichtlineare Datenstruktur Baum
e
c
Blatt
g
f
Grad=2
h
Wurzelbaum vom Grad 3
4
Datenstruktur Baum - Terminologie und Definitionen
Pfadlänge eines Weges: Zahl der
Kanten auf dem Weg von der Wurzel
zum Knoten.
Die Ebene (oder Stufe) eines Knotens
v ist die Länge des Pfades von der
Wurzel zu v:
Ebene der Wurzel = 0.
Ebene eines Knotens
v = (Ebene des Vorgängers von v)+1.
Ebene
0
d
k
b
a
Nichtlineare Datenstruktur Baum
1
e
c
Die Höhe des Baumes ist die maximale
Ebene seiner Knoten.
Das Gewicht eines Baumes ist die
Anzahl seiner Blätter.
20.01.2012
FB Informatik
Prof. Dr. R.Nitsch
g
f
2
i
3
Höhe = 3
5
Binärer Baum und binärer Suchbaum (BST: Binary Search Tree)
Wichtigster Sonderfall: Binärbaum =
Wurzelbaum mit Grad 2.
Definition eines binären Baums:
Ein binärer Baum ist entweder ein leerer
Baum oder ein Knoten, der mit einem
Paar von binären Bäumen verbunden ist.
Diese beiden Bäume bezeichnet man als
linken und rechten Teilbaum.
(Teil-)Bäume können auch leer sein.
Definition des binären Suchbaums (BST):
Knoten enthalten einen eindeutigen
Schlüsselwert.
Ein binärer Suchbaum ist ein binärer
Baum, bei dem die Knoten des linken
Teilbaums eines Knotens nur kleinere
Schlüsselwerte und die Knoten des
rechten Teilbaums eines Knotens nur
größere oder gleichgroße Werte
Schlüsselwerte als der Knoten selbst
besitzen (soweit es keine leeren
Teilbäume sind).
20.01.2012
d
Wurzel (root)
e
b
a
FB Informatik
Prof. Dr. R.Nitsch
c
g
Linker Teilbaum
f
Binärer Baum
und Binärer Suchbaum
Nichtlineare Datenstruktur Baum
h
Rechter Teilbaum
d
NULL
Links
Leere Teilbäume
(Manchmal auch als
externe Knoten bezeichnet)
6
Vollständiger und ausgeglichener binärer Baum
FB Informatik
Prof. Dr. R.Nitsch
Ein vollständiger Binärbaum enthält die für
seine Höhe maximale Anzahl von Knoten.
Genauere Definition: Ein vollständiger
Binärbaum der Höhe h hat folgende
Eigenschaften:
jeder Knoten der Ebene h ist ein Blatt
jeder Knoten der Ebene i < h hat genau 2
Nachfolger
1
f
b
a
c
e
h=2
g
vollständiger binärer Baum
Definition: Bei einem ausgeglichenen
0
f
Binärbaum
existiert ein k  0, so daß jedes Blatt auf
Ebene k oder k + 1 ist und jeder Knoten auf
einer kleineren Stufe als k hat Grad 2.
Definition: Ein entarteter Binärbaum liegt
vor, wenn jeder Elternknoten nur einen
Kindknoten hat
0
d
1
h
b
d
a
c
g
e
j
e
2
2
ausgeglichener binärer Baum
20.01.2012
Nichtlineare Datenstruktur Baum
7
Metriken und Eigenschaften von BST
FB Informatik
Prof. Dr. R.Nitsch
Maximale Anzahl von Knoten
Ebene
auf Ebene i: 2i für i ≥ 0
im vollständigen Binärbaum: 2h+1-1
Die max. Pfadlänge im BST ist
identisch mit seiner Höhe h.
0
Die max. Pfadlänge vollständiger oder
ausgeglichener Binärbaume mit n
Knoten ist vorhersagbar: max.
Pfadlänge = h = int(log2n)
1
e
b
1
1
a
c
2
2
Pfadlängen
20.01.2012
0
d
Nichtlineare Datenstruktur Baum
g
2
2
f
i
3
3
3
Höhe = 3
8
Zeitkomplexitäten der Operationen im (ausgeglichenen) BST
Wie sucht man nach einem Schlüsselwert (z.B.33)?
FB Informatik
Prof. Dr. R.Nitsch
Eingefügt werden die Schlüsselwerte:
80 47 96 20 15 60 25 42 73 23 33 37 28
 Eine erfolgreiche Suche (Suchtreffer) endet am gesuchten Knoten (Suchschlüssel). Der
Suchaufwand (= Anzahl Vergleiche) ist proportional zur Pfadlänge+1 < int(log2n)+1  O(log n)
Woran erkennt man, ob ein Suchschlüssel nicht existierte (z.B. 79)?
 Eine vergebliche Suche (Suchfehler) endet immer an einem leeren
Teil-Baum (erkennbar am NULL-Link zum Nachfolger). Leere Teilbäume
sind im Beispiel durch Rechtecke (externe Knoten) dargestellt.
 Aufwand wie bei erfolgloser Suche nach externem Knoten:
Pfadlänge zum externen Knoten+1 < int(log2n)+2  O(log n)
Wie fügt man im BST ein (z.B. Schlüsselwert 79)?
80
47
20
15
 Erfolgreiches Einfügen (keine Duplikate) beginnt wie eine
erfolglose Suche. Am Endpunkt der Suche, wird der externe Knoten
(NULL-Link) durch den einzufügenden Knoten ersetzt.
 Aufwand wie bei erfolgloser Suche nach externem Knoten:
Pfadlänge zum externen Knoten+1 < int(log2n)+2  O(log n)
 Die Einfügereihenfolge ist nicht rekonstruierbar!
Wie löscht man im BST einen Knoten (z.B. 37)?
 Löschen setzt eine erfolgreiche Suche voraus.
 Das Löschen selbst ist von konstanter Laufzeit:
 O(1) (kommt später)
Ein entarteter Baum entspricht einer Liste
96
60
25
23
73
42
33
28
37
Ergänzendes Beispiel: n = 1 000 000
mittl. Anzahl Vergleiche bei Suche
in verketteter Liste:
500 000
in BST:
20
 Aufwände siehe Liste: Suchen und Auswählen  O(n); Einfügen und Löschen:  O(1)
20.01.2012
Nichtlineare Datenstruktur Baum
9
Leistungsmerkmale von BST
FB Informatik
Prof. Dr. R.Nitsch
Der schnellste Suchalgorithmus, die "Binäre Suche" benötigt ld(n) Vergleiche im
Mittel. Sie setzt (sortierte) physikalische Sequenzen voraus, die Einfüge- und
Löschoperationen aber nur mit O(N) zulassen .
Die Suche in einem aus zufälligen Werten aufgebauten und nicht ausgeglichenen BST
benötigt im Mittel 1,39•ld(N) Vergleiche also O( ld n )
Die Suche im BST ist damit nur um etwa 40% aufwändiger als die binäre Suche. Der
Aufwand für die Einfüge- und Löschoperationen ist unabhängig von der Knotenanzahl
O(1) (wie bei logischer linearer Sequenz).
Beispiel eines Binären Suchbaums:
Enstanden durch Einfügen von etwa 200 zufälligen Werten in einen anfangs leeren Baum.
Eine Suche benötigt im Durchschnitt 10 Vergleiche, nie mehr als 12 Vergleiche. In einer
200-elementigen Liste wird man im Mittel erst nach 100 Vergleichen fündig!
20.01.2012
Nichtlineare Datenstruktur Baum
11
Verständnisfragen
FB Informatik
Prof. Dr. R.Nitsch
Um welchen Baumtyp handelt es sich?
3-wertiger Wurzelbaum
Wieviele Knoten?
Wieviele Blätter?
Welche Höhe?
Vollständig?
Ausgeglichen?
Entartet?
20.01.2012
K
F
L
S
13
C
7
3
A
H
D
M
O
X
Y
U
nein
nein
nein
Nichtlineare Datenstruktur Baum
12
Interne Darstellung eines Binären Suchbaums
FB Informatik
Prof. Dr. R.Nitsch
In Programmiersprachen mit Pointern bzw.
Referenzen (C, C++, Java, …): Knotenobjekte (z.B.
Typ Node) enthalten
d
Schlüsselwert und ggf zusätzliche assoziierte Daten
2 Pointer/Referenzen auf die Nachfolger
ggf zusätzlich 1 Pointer auf den Vorgänger
e
b
a
Wurzel (root)
c
g
f
h
Binärer Suchbaum
parent
struct Node {
Node( const K& t )
:key(t),left(0),right(0),parent(0) { }
~Node() { }
Node *left, *right, *parent;
K key;
parent
key
};
key K
left right
Datenstruktur in
struct Node
parent
K
left right
20.01.2012
Nichtlineare Datenstruktur Baum
key
K
left right
13
Implementierung eines BST Containers: class Tree
FB Informatik
Prof. Dr. R.Nitsch
typedef Any K;
struct Node
root
class Tree { // Implementation erlaubt keine Duplikate
lmost
parent
struct Node { /* siehe oben (eingeschachtelt) */ }
10
Node *root, *lmost; long size;
key K
size 5
public:
kleinstes Element im Baum
8
20
left right
typedef Node* link;
typedef long size_type;
15 30
typedef K key_type;
typedef K value_type;
Anforderungen an die Element-Klasse K
Tree() : root(0), lmost(0), size(0) { }
•Standard-Konstruktor
~Tree() { clear(); }
•Copy-Konstruktor
void clear();
class _Iter {
•bool K::operator<(const K&) const
link p;
•ostream& operator<<(ostream&,const K&);
public:
friend class Tree;
Welche Iterator-Kategorie?
_Iter( link ptr=0 ) : p(ptr) { }
Auch write-access? Sortierung? Abhilfe: const_Iter
K& operator* () const { return p->key; }
bool operator==( const _Iter it ) const { return p == it.p; }
bool operator!=( const _Iter it ) const { return p != it.p; }class Tree implementiert
ein Wörterbuch(dictionary)
_Iter& operator++();
}; // END class _Iter
typedef _Iter iterator;
Basisoperationen im Baum
friend class _Iter;
• Suchen
_Iter find( const K& t ) const { return findR(t, root ); }
std::pair<_Iter,bool> insert(const K& t){return insertR(t,root);} • Einfügen
• Entfernen
size_type erase( const K& t ) { return eraseR(t, root ); }
(=Wörterbuchoperationen)
14
Nichtlineare
Datenstruktur
Baum
/*20.01.2012
Deklaration der Hilfsfunktionen findR, insertR,
eraseR*/
};
Suchen im BST
FB Informatik
Prof. Dr. R.Nitsch
20.01.2011
_Iter Tree::find(const Key& key) { return findR(t,root);}
Rekursiver Algorithmus
für Suche im Baum
_Iter Tree::findR( const Key& key, link r ) const
Wenn der Teilbaum leer ist, liegt ein {
if( r==0 ) return end();// Base case 1: Suchfehler
Suchfehler vor.
Wenn der Suchschlüssel t
 kleiner als der Wurzel-Schlüssel ist,
suche im linken Teilbaum
 größer als der Wurzel-Schlüssel ist,
suche im rechten Teilbaum
 den Suchschlüssel enthält, liegt ein
Suchtreffer vor.
if( key<r->key ) return findR( key, r->left );
else if( r->key<key ) return findR( key, r->right );
else // Base case 2: r->key == key ; Suchtreffer!
return _Iter(r);
}
Wichtig: Algorithmus benötigt ausschliesslich K::operator<.
um Gleichheit (Äquivalenz) festzustellen. Dabei vergleicht
operator< nur die Schlüsselwerte der Knotenelemente.
20.01.2012
Nichtlineare Datenstruktur Baum
10
8
20
15
30
15
Einfügen in einen BST
50, 40, 43
Die Operation "Einfügen" hängt neue Knoten
immer als Blatt an.
 (a) linker Teilbaum hat nur kleinere Schlüsselwerte
als die Wurzel
 (b) rechter Teilbaum hat nur größere oder gleiche
Schlüsselwerte als die Wurzel
2 Schritte:
10, 8, 20, 10, 30
50
10
8
40
43
(a)
FB Informatik
Prof. Dr. R.Nitsch
20
10
30
Duplikat! (b)
 Suchen der Einfügestelle
Tree::iterator Tree::insert( const K& k ) { return insertR( k, root ); }
 Einketten (außer Duplikate)
pair<Tree::iterator,bool> Tree::insertR(const Key& key,link& r) {
// Füge Objekt k in subtree mit
if( r==NULL ) {
// Wenn der Subtree leer ist, wird t als Wurzelknoten eingefügt // Wurzel r ein (rekursiv)
r = new Node(key); // Fügt eine Kopie des Objekts t ein Hier ist wichtig, dass der link als Referenz
++size;
übergeben wurde: link& == Node*&
if( lmost == NULL ) lmost = r;
// Prüfen, ob neuer kleinster
parent
else if( r->key < lmost->key ) lmost = r;
// Wert vorliegt
return pair<_Iter,bool>(_Iter(r),true);
key
Node*&
}
// Gibt Iterator auf eingefügten Knoten zurück
left right
pair<_Iter,bool> success;
Node*
if( key < r->key ) // Objekt in linken subtree einfügen, wenn Schlüssel < Wurzel
{ success = insertR( key, r->left ); r->left->parent = r;
return success; } // Objekt in rechten subtree einfügen, wenn Schlüssel ≥ Wurzel
parent
else if( r->key < key )
key
{ success = insertR( key, r->right ); r->right->parent = r;
left right
return success; }
else return pair<_Iter,bool> (_Iter(r),false);
16
} 20.01.2012
Nichtlineare Datenstruktur Baum
Traversieren eines Binärbaumes
FB Informatik
Prof. Dr. R.Nitsch
Problem: Man möchte alle Daten, die in einem Binärbaum gespeichert sind, besuchen zum
Zwecke der Verarbeitung der assoziierten Daten; z.B. als Tabelle ausgeben oder ihre Anzahl
oder ihre Summe berechnen
Mit "Traversieren" eines Binärbaumes wird das systematische Besuchen all seiner Knoten
bezeichnet
Enthält ein Baum N Knoten, so gibt es N! (Fakultät) verschiedene Reihenfolgen, in welchen man
die Knoten eines Binärbaumes besuchen kann
Beispiel: Ein Baum mit den 3 Knoten A, B, C kann in 3! = 6 verschiedenen Reihenfolgen
traversiert werden
ABC
BAC
CAB
ACB
BCA
CBA
Die drei wichtigsten Traversierungsvarianten eines Baums werden mit Preorder, Inorder- und
Postorder-Reihenfolge bezeichnet und lassen sich rekursiv definieren:
 Preorder:
 Inorder:
 Postorder:
20.01.2012
Besuch der Wurzel, danach den linken und danach den rechten Teilbaum. Dort
wiederholt sich die Besuchsreihenfolge
Besuch des linken Teilbaums in Inorder-Reihenfolge, danach Besuch der
Wurzel, danach Besuch des rechten Teilbaums in Inorder-Reihenfolge
Besuch des linken Teilbaums in Postorder-Reihenfolge, danach Besuch des
rechten Teilbaums in Postorder-Reihenfolge, danach Besuch der Wurzel
Nichtlineare Datenstruktur Baum
17
Traversieren von BST
15.1.10
void Tree::toStreamRin( ostream& os, const link subtree ) const {
// visits all keys in sorted order (recursive inorder traversal)
if( subtree==NULL ) ; // nothing to do
else {
// print left subtree
toStreamRin( os, subtree->left );
// print key
os << subtree->key << ' '; // ostream& operator<<(ostream& os,const K&)
// erforderlich
// print right subtree
toStreamRin( os, subtree->right );
}
}
FB Informatik
Prof. Dr. R.Nitsch
g
4
c
a
1
2
k
f
j
3
5
6
m
7
in-order Reihenfolge
g
1
void Tree::toStreamRpre( ostream& os, const link subtree ) const {
c
k
// visits all keys in pre-order sequence
2
5
if( subtree==NULL ) ; // nothing to do
a
f
j
m
else {
3
4
6
7
// print key
os << subtree->key << ' ';
pre-order Reihenfolge
// print left subtree
toStreamRpre( os, subtree->left );
Anwendungen
// print right subtree
in-order Traversieren besucht Elem. sortiert
toStreamRpre( os, subtree->right );
}
pre-order Traversieren wird z.B. im Copy}
Konstruktor und operator= verwendet (erzeugt
exakte Baum-Kopie)
20.01.2012
Nichtlineare Datenstruktur Baum
18
Traversieren von BST
FB Informatik
Prof. Dr. R.Nitsch
void Tree::toStreamRpost( ostream& os, const link subtree ) const {
//visits all keys in post-order sequence recursive
if( subtree == NULL ) ; // nothing to do
else {
// print left subtree
toStreamRpost( os, subtree->left );
// print right subtree
toStreamRpost( os, subtree->right );
// print key
Anwendungen
os << subtree->key << ' ';
Post-order Reihenfolge wird
}
return;
z.B.beim Löschen eines Baums
}
angewendet
20.01.2012
Nichtlineare Datenstruktur Baum
g
7
c
a
1
3
k
f
j
2
4
6
m
5
post-order Reihenfolge
19
Klasse Tree: Copy-Konstruktor und Zuweisung
Tree( const Tree& toCopy ) {
root = NULL; lmost=NULL; size=0;
copyR( toCopy.root );
}
Copy-Konstruktor
Leeren Baum erzeugen
Source-Tree kopieren
FB Informatik
Prof. Dr. R.Nitsch
g
c
2
1
k
5
a
f
j
m
void Tree::copyR( link subtree ) {
3
4
6
7
// Rekursiver Algorithmus (Traversieren in preorder Reihenfolge)
// Erstellt eine exakte Kopie des Teilbaums
pre-order Reihenfolge
if( subtree == NULL )
; // Nichts mehr zu kopieren
else {
this->insert( subtree->key );
// Kopie der Wurzel in Zielbaum (this) einfügen
this->copyR ( subtree->left ); // linken Teilbaum kopieren
this->copyR ( subtree->right ); // rechten Teilbaum kopieren
}
}
Pre-order
Reihenfolge
Anwendung im Zuweisungsoperator
Tree& Tree::operator=( const Tree& r_value ) {
if( this == &r_value ) return *this; // self assignment
this->clear();
Bisherigen Inhalt des L-value löschen
this->copyR( r_value.root );
Source-Tree kopieren
}
20.01.2012
Nichtlineare Datenstruktur Baum
20
Baum fällen in C++
FB Informatik
Prof. Dr. R.Nitsch
void Tree::clear() { clearR( root ); lmost = 0; }
void Tree::clearR( link& subtree ) {
// deletes subtree with root subtree using post-order traversal
if( subtree!=NULL ) {
clearR( subtree->left ); //erase left subtree
post-order
clearR( subtree->right ); //erase right subtree
Reihenfolge
delete subtree ;
//erase root
subtree = NULL;
//and replace with external node
--size;
}
return;
}
g
7
c
a
1
3
k
f
j
2
4
6
m
5
post-order Reihenfolge
Anwendung im Destruktor
~Tree() { clear(); }
20.01.2012
Nichtlineare Datenstruktur Baum
21
Rekursive Berechnung von Baummetriken
FB Informatik
Prof. Dr. R.Nitsch
Rekursive Ermittlung der Knotenanzahl (Alternative zur Zählung mittels speziellem
Attribut):
private: long Tree::countR( link subtree ) { // zähle Knoten im Teilbaum
if ( subtree==NULL ) return 0; // Base case: "Da ist kein weiterer Knoten mehr!"
return countR( subtree->left )
// Zähle Knoten im linken Teilbaum
+ countR( subtree->right ) // Zähle Knoten im rechten Teilbaum und addiere hinzu
+ 1; // Das ist für den Wurzelknoten
root
Erklärung?
Besuchsreihenfolge?
}
10
public: long Tree::count() {
return countR( root );
}
// zähle Knoten im gesamten Baum
8
Rekursive Ermittlung der (Teil-)Baum-Höhe:
20
10
30
private: long heightR( link subtree ) {
if ( subtree==NULL ) return 0;
Externer Knoten: Höhe=0 -> base case
long hl = heightR( subtree->left );
Bestimme Höhe des rechten Teilbaums
long hr = heightR( subtree->right ); Bestimme Höhe des linken Teilbaums
if( hl>hr ) return hl+1; else return hr+1;
Wurzelknoten liegt 1 Ebene höher
als seine Teilbäume!
}
public: long getHeight() {
return heightR( root );
}
20.01.2012
Nichtlineare Datenstruktur Baum
22
Ausgabe der Baumstruktur als Textsequenz
21.1.2011
FB Informatik
Prof. Dr. R.Nitsch
Anwendung: Unterstützung beim Debuggen von Algorithmen mit Bäumen
private: void Tree::toStreamR( ostream& os, link r, int indent ) {
if( r==NULL ) {
os << string(indent , ' ' ) << '*' << endl; // Externer Knoten -> base case
return;
}
toStreamR( os, r->right, indent+1 );
os << string(indent, ' ' ) << r->key << endl;
inorder traversieren
toStream( os, r->left, indent+1 );
}
public: void toStream( ostream& os ) { toStreamR( os, root, 0 ); }
Beispiele: Einfügesequenz: 1, 2, 3, 4
Ausgabe:
*
4
*
3
indent
Ausgabe:
In welcher Reihenfolge müssen die Knoten
zur Ausgabe besucht werden?
*
4
*
3
*
2
*
1
*
20.01.2012
Einfügesequenz: 3, 1, 2, 4
*
2
*
1
*
Hausaufgabe: Modifizieren Sie den
Quellcode für den Fall, dass die Feldbreite für
info w Zeichen (w>1) beträgt.
Nichtlineare Datenstruktur Baum
23
Löschen von einzelnen Elementen im Baum
Fallunterscheidung
1. Zu löschendes Element D ist ein Blatt:
Entferne Blatt
FB Informatik
Prof. Dr. R.Nitsch
vorher
nachher
D
vorher
nachher
2. Zu löschendes Element D hat genau einen
Nachfolger N: Ersetze D durch N
N
D
N
3. Zu löschendes Element D hat 2 Nachfolger
DL und DR:
Methode 2: Ersetze Schlüsselwert im Element D
Methode 1: Ersetze D durch den linken
durch eine Kopie des größten Schlüsselwerts im
Nachfolger DL und mache den rechten
linken Teilbaum von D (Element R) und lösche R.
Nachfolger DR zum rechten Nachfolger des
vorher
nachher
größten Elements R des linken Teilbaums von D
vorher
nachher
D
R
D
DL
DR
DL
R
20.01.2012
DR
DL
R
R
DR
RL
Nichtlineare Datenstruktur Baum
DL
DR
RL
Vorteil: Geringere Auswirkung
auf die Ausgeglichenheit
24
Löschen von einzelnen Elementen im Baum
FB Informatik
Prof. Dr. R.Nitsch
// Schlüsselwert k suchen und entfernen
Tree::size_type Tree::erase( const Key& key ) {
// Nichts zu tun; nichts gelöscht
if( empty() ) return 0;
size_type numberOfErasedNodes = eraseR( key, root );
// nur 0 und 1 sind mögliche Werte (keine Duplikate im Tree!)
return numberOfErasedNodes;
}
Tree::size_type Tree::eraseR( const Key& key, link& subtree ) // class Tree erlaubt keine Duplikate
{
// search key
if( subtree==NULL ) return 0; // Base case 1: (Teil)Baum leer; nichts zu löschent
if( key < subtree->key )
// key k aus linkem Subtree entfernen
return eraseR( key, subtree->left );
else if( subtree->key < key ) // key k aus rechtem Subtree entfernen
return eraseR( key, subtree->right );
// Base case 2: Key an Wurzel des Subtree gefunden.
// Beachte: Der Löschkandidat wird gefunden
// ohne den Aquivalenzoperator für den
// key_type zu benutzen!
else // subtree->key == key
// Zeiger auf gefundenes Lösch-Element zur besseren Lesbarkeit des Codes
{
link d = subtree;
// Fall 1: Zu löschendes Element ist ein Blatt (keine Nachfolger)
if( d->left==NULL && d->right==NULL ) vorher
// Schlüssel ausketten
{
subtree = NULL;
// Schlüssel löschen
delete d; --size;
return 1;
}
20.01.2012
nachher
D
Nichtlineare Datenstruktur Baum
25
Löschen von einzelnen Elementen im Baum
FB Informatik
Prof. Dr. R.Nitsch
if( d->left==NULL) {
vorher
nachher
// Fall 2: Nur rechter Nachfolger
subtree = d->right;
// Schlüssel ausketten
sroot
D
subtree->parent = d->parent;
delete d; --size; return 1;
// Schlüssel löschen
}
nachher
vorher
else if( d->right==NULL) {
// Fall 2: Nur linker Nachfolger
subtree = d->left;
sroot
// Schlüssel ausketten
D
subtree->parent = d->parent;
// Schlüssel löschen
delete d; --size; return 1;
}
else // d->left!=NULL && d->right!=NULL // Fall 3: 2 Nachfolger
return erase2child( d->left, d );
// Maximum aus linkem Subtree
// ins ple-Element kopieren und löschen
} //else subtree->key == k
}
size_type erase2child( link& subtree, link& d ) {
if( subtree->right!=NULL ) // Solange rechts weitersuchen, bis Maximum gefunden
return erase2child( subtree->right, d );
vorher
else {
// subtree->right != 0; Maximum r gefunden
ple
link r = subtree;
// Verbessert Lesbarkeit
l
d->key = r->key;
// r nach d kopieren
sroot
// wenn r kein Blatt…
if(r->left!=NULL)
// … rl an Stelle von r
r->left->parent = r->parent;
s
LR
LL
// einketten
subtree = r->left;
r
delete r; --size; return 1;
// r löschen
rl
}
}
20.01.2012
Nichtlineare Datenstruktur Baum
nachher
r
LL
s
LR
rl
26
Der Tanz der Bäume - Rotationen und ihre Anwendungen
Eine Rotation vertauscht die Rolle
vorher
B
einer Wurzel (S bzw. B) mit einem
ihrer unmittelbaren Nachfolger (E).
Eine Rechts-(Links-)Rotation wirkt auf
die Wurzel und den linken (rechten)rotierendes Element E
Nachfolger
Durch eine Rechts-Rotation wird das
el
rotierende Element und sein linker
Teilbaum um eine Ebene angehoben
während die Wurzel (S) und ihr
rechter Teilbaum um eine Ebene
vorher
abgesenkt wird.
Entsprechendes gilt für die LinksB
Rotation.
Anwendungen
Einfügen an der Wurzel
Löschen von Elementen in
ausgeglichenen BST
FB Informatik
Prof. Dr. R.Nitsch
Wurzel
nachher
B
S
E
S
sr
el
er
er
sr
E≤ Schlüsselwerte <S
nachher
S
S
E
E
B
er
bl
el
er
bl
el
Rechtsrotation (oben) und Linksrotation (unten)
20.01.2012
Nichtlineare Datenstruktur Baum
27
Einfügen an der Wurzel in einem BST
A
Standardimplementierung: Zuletzt eingefügte
Schlüssel haben immer einen langen Suchpfad:
Sie bilden ein Blatt im Baum.
Wenn Anwendungen auf neu eingefügte Elemente
öfter zugreifen als auf andere, sollte man besser
an der Baumwurzel einfügen.
Für die dabei auftretenden Probleme gibt es eine
Lösung: Einfügen als Blatt und rekursive
Anwendung von Rotationen:
1.
2.
3.
4.
5.
G als Blatt einfügen
Rechts-Rotation
Links-Rotation
Rechts-Rotation
Links-Rotation
20.01.2012
X
C
E
R
1
S
C
G
R
X
4
A
G
S
E
C
A
S
X
E
G
2
R
X
C
R
G
E
3
A
Vorher
E
G
5
S
G
C
S
A
A
Probleme beim
Einfügen an
L
der Wurzel
FB Informatik
Prof. Dr. R.Nitsch
A
R
L
C
R
Fehler!
X
R
C
Wenn man auch die Operation "Suchen" so ändert,
daß jeder Suchtreffer durch rekursive Rotationen
an die Wurzel befördert wird, erhält man ein
selbstorganisierendes Suchverfahren, das häufig
angesprochene Elemente an der Wurzel sammelt.
Nachher
Nichtlineare Datenstruktur Baum
28
22.1.2010
Die Grundschritte - Implementation der Rotationstransformationen
void Tree::rotR( link& s ) {
vorher
b
//
Linker
Subtree
von
s
fehlt;
nichts
zu
rotieren.
if(e==NULL) return;
// Linken Subtree mit Wurzel e von s abkoppeln
link e = s->left;
s
if(e->right!=NULL) { // Wenn rechter Subtree von e existiert
e
// Rechter Subtree von e wird neuer linker Subtree von s
s->left = e->right;
sr
// Rückwärtslink von er nach s
e->right->parent = s;
// Nichts anzubinden -> ext. Knoten
} else s->left = NULL;
el
er
// s als rechten Subtree an e anbinden
e->right = s;
e->parent = s->parent;
// Rückwärtslink von e zu b
s->parent = e;
// Rückwärtslink von s zu e
s = e;
// e an b anbinden
Rotation = Rollentausch
}
zwischen Wurzel und
void Tree::rotL( link& b ) {
link e = b->right;
if(e==NULL) return;
if(e->left!=NULL) {
b->right = e->left;
b->right->parent = b;
} else b->right = NULL;
e->left = b;
e->parent = b->parent;
b->parent = e;
b = e;
}
20.01.2012
FB Informatik
Prof. Dr. R.Nitsch
e
s
el
er
Nichtlineare Datenstruktur Baum
vorher
sr
parent
key K
left right
einem ihrer Nachfolger
// Rechten Subtree mit Wurzel e von b abkoppeln
// Rechter Teilbaum von s fehlt; nicht zu rotieren.
// Wenn rechter Subtree von e existiert
// Linker Subtree von e wird neuer rechter Subtree von b
// Rückwärtslink von el nach b
// Nichts anzubinden -> ext. Knoten
// b als linken Subtree an e anbinden
// Rückwärtslink von b nach s
bl
// Rückwärtslink von b nach e
// e an s anbinden
nachher
b
nachher
s
b
s
e
e
b
er
el
er
bl
el
29
Algorithmus zum Einfügen an der Wurzel
FB Informatik
Prof. Dr. R.Nitsch
Im vorigen Beispiel wurde die Einfügestelle für G am Ende des Suchpfades A-T-E-R gefunden.
Entlang dieses Suchpfades wird das Einfügeelement durch Rotationen zur Wurzel gebracht.
Bei jedem Rotationsvorgang ist die Richtung der Rotation des Vorgängerelements gegeben durch
das Kindschaftsverhältnis zum Vorgängerknoten: Einfügeelement ist
 linkes Kind
 rechtes Kind
-> Rechtsrotation des Vorgängerknotens
-> Linksrotation des Vorgängerknotens
Das Einfügeelement wird zur Wurzel, wenn jeder Knoten des Suchpfades einmal rotiert wurde.
A
void insertRootR( const Key& key, link& s ) {
T
// Einfügeposition erreicht; Ende des Suchpfades (base case)
if( s==0 ) {
E
s = new Node( key );
// Einfügen als Blatt
C
R
return;
1
G
}
if( key < s->key ) {// beim linken Nachfolger weiter suchen
insertRootR( key, s->left ); rotR( s );
// danach Rechtsrotation des Knotens
} // beim rechten Nachfolger weiter suchen // danach Linksrotation des Knotens
else {
*
Baumstruktur *
Baumstruktur
insertRootR( key, s->right ); rotL( s );
5
5
vor dem
nach dem
*
}
*
Einfügen:
Einfügen des
4
4
}
Elements k=2:
*
*
public: _Iter insertRoot( const Key& key ) {
insertRootR( key, root );
return begin();
}
20.01.2012
Nichtlineare Datenstruktur Baum
3
3
*
1
X
*
2
*
*
1
*
30
Nocheinmal: Löschen von einzelnen Elementen im Baum (Methode 3)
Bilde aus linkem und rechtem Teilbaum des Löschelements
D einen Verbundbaum (Methode joinLR). Dieser wird an
Stelle des Löschelements mit dessen Vorgänger verbunden.
Suche dazu kleinsten Schlüsselwert M im rechten
Teilbaum und mache diesen zur Wurzel des rechten
Teilbaums (wird von min2root geleistet) und
Mache den linken Teilbaum zum linken Nachfolger der
neuen Wurzel M.
vorher
FB Informatik
Prof. Dr. R.Nitsch
nachher
D
DL
M
DR
M
DL
DR'
Implementierung
public: size_type Tree::erase( const K& key ) {
return eraseR( key, root );
}
Rekursive Löschmethode eraseR sucht Schlüsselwert k im (Teil)Baum mit Wurzel r und entfernt dieses Element.
private: size_type Tree::eraseR( const K& key, link& r ) {
if(r==NULL) return 0; // base case: externer Knoten erreicht; Löschschlüssel nicht gefunden!
if( key<r->key ) return eraseR( key, r->left ); // im linken Teilbaum weiter suchen
else if( r->key<key ) return eraseR( key, r->right ); // im rechten Teilbaum weiter suchen
else {
// k bei r gefunden
link d = r;
// Verbindung zu Löschknoten in d temporär halten
r = joinLR( d->left, d->right );
// joinLR verbindet rechten und linken Teilbaum und gibt Zeiger
if(r!=NULL) r->parent = d->parent;
// auf neue Wurzel zurück. Diese wird an den Vorgänger des
delete d; --size; return 1;
// Löschknotens angekoppelt
}
}
20.01.2012
Nichtlineare Datenstruktur Baum
31
Nocheinmal: Löschen von einzelnen Elementen im Baum (Methode 3)
FB Informatik
Prof. Dr. R.Nitsch
link joinLR( link a, link b ){ // Teilbäume a und b verbinden; Zeiger auf Verbundbaum-Wurzel zurück geben
if( b==NULL ) return a;
// rechter Teilbaum ist leer; a ist schon Verbundbaum-Wurzel
min2root( b );
// Minimum in rechtem Teilbaum suchen und zur Wurzel machen
b->left = a;
// linken Teilbaum an Wurzel b anhängen
if( a!=NULL ) a->parent = b; // Wenn linker Teilbaum nicht leer ist
return b;
// Neue Verbundbaum-Wurzel zurückgeben
}
void min2root( link& r )
{
if( r->left != NULL ) {
min2root( r->left );
rotR( r );
}
assert( r->left==NULL );
return;
}
// Macht kleinsten Schlüsselwert eines (Teil)Baums zur Wurzel
// In die linken Teilbäume hinabsteigen bis Blatt (=Nachfolger des Löschelements)
// erreicht ist. Danach dieses Blatt mittels Rechtsrotationen zur Wurzel machen
// Nachbedingung: Der linke Teilbaum zur Wurzel muss leer sein
vorher
nachher
D
DL
DR
M
20.01.2012
Nichtlineare Datenstruktur Baum
M
DL
DR'
32
Bewertung von BST
FB Informatik
Prof. Dr. R.Nitsch
Vorteile
Einfüge- und Löschoperationen von O(1)
Suchoperationen bestenfalls von O(log(N))
Nachteile:
Hoher Speicheraufwand für die Verbindungen
Die fehlende Ausgeglichenheit von BST läßt keine Leistungsgarantien zu:
o Bereits sortierte (auch umgekehrt sortierte) Dateien,
o Dateien mit vielen mehrfachen Schlüsseln,
o Dateien mit abwechselnd großen und kleinen Schlüsseln
können zu entarteten BST und damit quadratischen Konstruktionszeiten O(N2) und linearen Suchzeiten
O(N) führen
Abhilfe: Algorithmen, die einen BST explizit ganz neu ausgleichen (z.B. nach fester Anzahl von
Einfügen- und Löschoperationen.
20.01.2012
Nichtlineare Datenstruktur Baum
33
Algorithmus zum Ausgleichen eines BST
FB Informatik
Prof. Dr. R.Nitsch
Idee:
1
Median im BST suchen und an die Wurzel bringen: Linker
und rechter Teilbaum enthalten N/2 bzw. N/2-1 Knoten.
Gleiches mit den Teilbäumen rekursiv wiederholen bis
Teilbäume leer sind.  balanceR
benötigt wird dazu:
partR: Ein Algorithmus, der das k-kleinste Element
auswählt und danach an die Wurzel bringt; für k=N/2 ist
dies der Median
Vorher
2
3
4
4
2
1
5
6
3
5
6
7
7
Nachher
void Tree::balanceR( link& subtree )
// base case: externer Knoten oder Blatt (Nichts zu partitionieren)
{
if(subtree==NULL || countR(subtree)==1) return;
partR(subtree, countR(subtree )/2 ); // Median bestimmen und zur Wurzel rotieren
balanceR( subtree->left );
// Gleiches für linken und rechten Teilbaum wiederholen
balanceR( subtree->right );
}
void partR( link& subtree, int k ) {
int n = countR(subtree->left);
// n: Knotenanzahl im linken Teilbaum
if(k<n) {
// k-kleinstes Element muß im linken Teilbaum sein
partR(subtree->left,k); rotR(subtree);
} else if(n<k) {
// k-kleinstes Element muß im rechten Teilbaum sein.
partR(subtree->right,k-n-1); rotL(subtree);
// Dort ist es aber das (k-n-1)-kleinste!
} else ;
return;
34
Nichtlineare Datenstruktur Baum
} 20.01.2012
Rot-Schwarz-Bäume
FB Informatik
Prof. Dr. R.Nitsch
Das gelegentliche vollständige Ausgleichen (z.B nach einer bestimmten Anzahl von
Einfüge/Lösch-Operationen) verbessert die Leistungsfähigkeit eines BST nur begrenzt.
Insbesondere können immer noch keine Leistungsgarantien gegeben werden, weil die
Höhe log(N) nicht immer garantiert ist.
Sortierte höhen-balancierte Schlüsselbäume bieten hier mehr: Die Operationen Einfügen
und Suchen sind in höhen-balancierten Bäumen am schnellsten. Allerdings steigt bei
diesen der algorithmische Aufwand:
Unzulässige Höhenunterschiede zweier Teilbäume müssen erkannt und mittels Rotationen
beseitigt werden.
Ein bekannter Vertreter dieser Spezies ist der Rot-Schwarz-Baum (Red-Black-Tree). Die
assoziativen STL-Container gehören auch dazu.
RBT verwalten ein zusätzliches Farbattribut pro Knoten
RBT mit N internen Knoten garantieren:
maximale Pfadlänge <= 2 * minimale Pfadlänge
Baumhöhe <= 2 log (N+1)
Suchen, Auswählen -> O(log N) garantiert
20.01.2012
Nichtlineare Datenstruktur Baum
35
Definition und weitere Eigenschaften
FB Informatik
Prof. Dr. R.Nitsch
Ein Rot-Schwarz-Baum (RBT) ist ein sortierter binärer Schlüsselbaum mit folgenden
Eigenschaften (Invarianten):
1.
2.
3.
4.
Jeder Knoten ist entweder rot oder schwarz (RB1)
Jeder externe Knoten ist schwarz (RB2)
Rote Knoten haben immer 2 schwarze Söhne (RB3)
Alle Pfade von externen Knoten zur Wurzel enthalten dieselbe Anzahl schwarzer Knoten (RB4)
Beispiel für einen RBT
K
F
C
A
S
H
D
B
O
L
X
class Tree {
enum Color { RED='r', BLACK='s'};
struct Node {
Node(const K& k, Color c=BLACK)
:key(k),left(0),
right(0),parent(0),
Black is nobly
color(c) { }
~Node() { }
U
Node *left, *right, *parent;
K key; Color color;
E
};
typedef Node* link;
// Rest wie gehabt
Externe Knoten sind alle schwarz und nicht dargestellt!
};
20.01.2012
Nichtlineare Datenstruktur Baum
36
Einfügen und Suchen in einem RBT
FB Informatik
Prof. Dr. R.Nitsch
Algorithmische Konsequenzen:
Das Suchen funktioniert wie beim BST-Tree -> Laufzeit O(h)=O(log N)
Das Einfügen eines Knotens x erfolgt zunächst wie beim BST. Falls dabei Eigenschaft 3 oder 4
verloren geht, muss die Farbstruktur des Baumes repariert werden.
RB1: Jeder Knoten ist entweder rot oder schwarz
RB2: Jeder externe Knoten ist schwarz
RB3: Rote Knoten haben immer 2 schwarze Söhne
RB4: Alle Pfade von externen Knoten zur Wurzel enthalten dieselbe Anzahl schwarzer Knoten
Einfügen eines Knotens x erfolgt zunächst immer als Blatt.
Dabei wird x immer rot eingefärbt.
Grund: weniger Farbkorrekturen, weil
- Bei schwarzem x würde immer RB4 verletzt!
- Bei rotem x wird nur dann eine Regel (RB3) verletzt,
3
wenn der Vater von x auch rot ist (s. Beispiel).
Farben reparieren
6
o
g
6
12
Wenn das rote x auch einen roten Vater v hat,
x
unterscheidet man:
8
Fall 1: Onkel o von x (3) ist auch rot (RB3 verletzt)
Lösung: o und v schwarz machen
Problem: Jeder Pfad über den Großvater g hat jetzt
Neu eingefügt!
einen zusätzlichen schwarzen Knoten.
Lösung: g rot machen
Konsequenz: RB3&4 können jetzt 2 Etagen höher wieder verletzt sein!
20.01.2012
Nichtlineare Datenstruktur Baum
v
3
g
o
12
8
x
37
v
Einfügen in einem RBT - Implementierung
FB Informatik
Prof. Dr. R.Nitsch
pair<Tree::_Iter,bool> Tree::insert_rb( const Key& key ) {
if( root!=NULL ) assert( root->color == BLACK ); // Die Wurzel ist immer schwarz
pair<_Iter,bool> success = insertR( key, root ); // insertR wird wiederverwendet
if (success.second==false) return success;
// Duplikat! Nichts eingefügt -> Korrekturen überflüssig!
// Akteure für Korrekturen definieren
link x = success.first.nodePtr; // Eingefügter ( standardmäßig scharzer) Knoten
link v = x->parent;
// Vater von x
if( v==NULL ) return success;
// x ist Baumwurzel; fertig
link g = v->parent;
// Grossvater von x
link o = NULL;
// Onkel von x; noch unbekannt
Color ocolor;
// Farbe des Onkels
x->color = RED;
// Eingefügt wird immer zunächst als roter Knoten
if( g==NULL ) return success;
// Vater ist Wurzelknoten und daher schwarz; x ist jetzt rot -> alles ok!
// Vater und Großvater existieren
6
3
g
o
12
8
20.01.2012
Nichtlineare Datenstruktur Baum
v
x
Neu eingefügt!
38
Einfügen in RBT - Implementierung
FB Informatik
Prof. Dr. R.Nitsch
// Vater und Großvater existieren // RBT-Invarianten müssen geprüft werden
if( v->color==RED )
// Roter Vater (v) mit rotem Sohn (x) -> RB3 verletzt
{
while( x!=root && v->color==RED //) Auf dem Weg zur Wurzel dürfen keine 2 roten Knoten
{ // Akteure neu bestimmen
// aufeinander folgen (RB3)
g = v->parent;
// g ist Großvater von x
if( v==g->left )
// Wenn Vater linker Sohn des Großvaters ist
{
// dann ist Onkel von x der rechte Sohn des Großvaters
o = g->right;
g
6
if(o==NULL) ocolor = BLACK; // Ein nil-Onkel ist immer schwarz->Fall 2
else ocolor = o->color;
if( ocolor==RED )
// Fall 1: Roter Vater und roter Onkel
{
o
3
12 v
// Vater umfärben
v->color = BLACK;
// Onkel umfärben
o->color = BLACK;
// Großvater umfärben
g->color = RED;
x
8
// Hier ist jetzt alles erledigt // aber 2 Stufen höher jetzt alles nochmal
// Deshalb Akteure neu bestimmen
// Fortsetzen als wäre soeben roter g eingefügt worden
x = g;
// v ist Vater von x
v = x->parent;
Neu eingefügt!
// Fall2: Roter Vater und schwarzer Onkel
} else //ocolor is BLACK
20.01.2012
Nichtlineare Datenstruktur Baum
39
Einfügen in einem RBT
FB Informatik
Prof. Dr. R.Nitsch
RB1: Jeder Knoten ist entweder rot oder schwarz (RB1)
RB2: Jeder externe Knoten ist schwarz (RB2)
RB3: Rote Knoten haben immer 2 schwarze Söhne (RB3)
RB4: Alle Pfade von externen Knoten zur Wurzel enthalten dieselbe Anzahl schwarzer Knoten
Fall 2: Onkel o von x ist schwarz oder nil
-> Farben reparieren durch rotieren!
Hinweis: nil steht für "not in list" und steht für einen
nicht existierenden (=externen) Knoten.
Fall 2a: x ist linker Sohn seines Vaters v.
1. Vater v (5) schwarz färben -> RB4 verletzt
2. Großvater g wieder rot färben -> RB4 verletzt
3. R-Rotation um g (9) -> fertig, alles ok!
1.
9
5
2
v
x
2.
g
9
o
5
2
x
v
g
9
o
5
2
v
3.
g
o
5
2
9
v
x
Neu eingefügt!
20.01.2012
Nichtlineare Datenstruktur Baum
40
Einfügen in einem RBT
FB Informatik
Prof. Dr. R.Nitsch
RB1: Jeder Knoten ist entweder rot oder schwarz (RB1)
RB2: Jeder externe Knoten ist schwarz (RB2)
RB3: Rote Knoten haben immer 2 schwarze Söhne (RB3)
RB4: Alle Pfade von externen Knoten zur Wurzel enthalten dieselbe Anzahl schwarzer Knoten
Fall 2: Onkel o von x ist schwarz oder nil
-> Farben reparieren durch rotieren!
Hinweis: nil steht für "not in list" und steht für einen
nicht existierenden (=externen) Knoten.
Fall 2b: x ist rechter Sohn seines Vaters v.
1. L-Rotation um v (5) -> Fall 2a
2. Rest wie Fall 2a
Fall 2a
Fall 2a, 1. bis 3.
1.
9
5
v
g
9
g
7
o
v
x
5
7
9
g
v
7
x
5
Rollentausch!
x
Neu eingefügt!
20.01.2012
Nichtlineare Datenstruktur Baum
41
Einfügen in RBT - Implementierung
{
if( x==v->right ) {
rotL(g->left);
x = v;
v = x->parent;
}
v->color = BLACK;
g->color = RED;
FB Informatik
Prof. Dr. R.Nitsch
// Fall 2: Roter Vater und schwarzer Onkel
// Fall 2b: x ist rechter Sohn
// erst in Fall 2a umwandeln
// Rollentausch zwischen v und x
// Ab hier Fall 2a
// Vater umfärben
// Großvater auch
// Farben durch Rotation um g reparieren
// Von wem stammt der Großvater ab: Urgroßvater oder Gott/Allah (root) ?
// Großvater hat einen Urgroßvater dessen linker oder rechter Sohn er ist
if( g->parent )
g->parent->left==g ? rotR( g->parent->left ) : rotR( g->parent->right );
else
// Großvater ist Adam und hat keinen Vorgänger ausser root
rotR( root );
} // END ELSE ocolor is BLACK
} else // END if( v==g->left ) Vater ist linker Sohn des Großvaters
{ // Vater ist rechter Sohn des Großvaters
...
// Das ganze nochmal, aber rechts und links vertauschen, auch bei den Rotationen
}
}
}
// END while( x!=root && v->color==RED )
else ; //END IF(v->color==RED)
// Schwarzer Vater mit rotem Sohn. Keine RBT-Regel verletzt
root->color = BLACK; Die Wurzel ist immer schwarz
return success;
}
20.01.2012
Nichtlineare Datenstruktur Baum
42
Algorithmus zum Testen der RBT-Eigenschaften
FB Informatik
Prof. Dr. R.Nitsch
bool isRBTree()
{
isRBT = true;
blackHeight = -1; // Anzahl schwarzer Knoten auf dem Weg von der Wurzel zu einem Blatt (Attribut von Tree)
if (root!=NULL) return isRBTreeR( root, 0 ); else return true ;
}
bool isRBTreeR( link r, int bheight ) {
// Schwarzhöhe für diese Aufrufebene aktualisieren
if ( r->color==BLACK ) ++bheight;
if(r->left==NULL && r->right==NULL) { // Blatt erreicht? (base case)
if( blackHeight==-1 ) {
// Wenn dies erstes Blatt ist braucht RB4 noch nicht geprüft werden ...
blackHeight = bheight;
// aber der Referenzwert für die Schwarzhöhe muss gemerkt werden.
return true;
// Regel RB3: externe Knoten sind immer schwarz (RB2)
}
else
// Alle weiteren Blätter müssen die gleiche
return (blackHeight==bheight) ? true : false; // Schwarzhöhe haben
}
if( r->left ) isRBT = isRBT && isRBTreeR(r->left, bheight ); // Blätter im linken Teilb. suchen
if( r->right ) isRBT = isRBT && isRBTreeR(r->right, bheight ); // Blätter im rechten Teilb. suchen
if( r->color==RED ) { // RB3 prüfen: Rote Väter haben stets 2 schwarze Knaben
if(r->left)
isRBT = isRBT && ( r->left->color==BLACK );
if(r->right)
isRBT = isRBT && ( r->right->color==BLACK );
}
return isRBT;
}
20.01.2012
Nichtlineare Datenstruktur Baum
43
Algorithmus zum Testen des Einfügealgorithmus
FB Informatik
Prof. Dr. R.Nitsch
void testInsert_RB()
{
Tree tree;
for( int m=0; m<100; ++m ) {
srand(m);
for ( int i=0; i<10000; ++i ){
tree.insert_rb( rand() );
}
assert( tree.isRBTree() );
tree.clear();
}
}
Aufgabe: Zeichnen Sie die RBT-Baumstruktur nach dem Einfügen folgender Zahlenfolgen:
5362
5364
531
534
20.01.2012
Nichtlineare Datenstruktur Baum
44
FB Informatik
Prof. Dr. R.Nitsch
So, das war´s!
Was vergessen?
20.01.2012
Nichtlineare Datenstruktur Baum
45
Herunterladen