Microsoft PowerPoint - 05 B\344ume 2 - informatik.uni

Werbung
Universität Bremen
Universität Bremen
Bäume 2
Rückblick „Bäume 1“
Begriffe
Thomas Röfer
Suchbäume
Suchen, Einfügen, Löschen
Balancierte Bäume (AVL-Bäume)
B-Bäume
Durchlaufen von Bäumen
Spielprobleme
Huffman-Baum
1
Eigene Züge
Eigene Züge
H
PI-2: Bäume 2
9
0
A
G
F
E
D
C
2
Universität Bremen
Suchbäume
Normaler Suchbaum
Ansatz
Motivation
Ein Suchbaum dient zum schnellen
Auffinden von Werten, möglichst in O(log n)
Werte stehen in inneren Knoten
Blätter sind leer
Definition
Suchalgorithmus
Die Schlüssel aller linken Nachfolger sind
kleiner als der Schlüssel eines Knotens, die
Schlüssel aller rechten sind größer (oder
gleich)
Ein natürlicher Baum wird durch zufälliges
Einfügen von Schlüsseln erzeugt und ist
nicht notwendigerweise balanciert
Fall 1: Knoten ist innerer Knoten
27 … 39 39 … ∞
Alternative Schreibweise
-∞ … 1
1…3
15 … 27
Sichtweise
Die Blätter repräsentieren Intervalle im
Wertebereich der Schlüssel
PI-2: Bäume 2
3 … 14
Falls Schlüssel gleich gesuchtem
Wert, dann gefunden
Ansonsten abhängig von Vergleich
zwischen Wert und Schlüssel links
oder rechts weitersuchen
Fall 2: Knoten ist Blatt
nicht gefunden
Wert
Aufwand
14 … 15
O(Höhe des Baumes)
3
Universität Bremen
PI-2: Bäume 2
4
Universität Bremen
Blattsuchbäume
Suchen in Suchbaum
Ansatz
Wenn gesuchter Wert
Geordnet wie Suchbäume
Werte stehen in Blättern
Innere Knoten enthalten nur
„Wegweiser“
gleich dem Schlüssel
gefunden
kleiner als Schlüssel
weitersuchen in linkem Nachfolger
ansonsten
weitersuchen in
rechtem Nachfolger
z.B. größten Wert des linken Teilbaums
Suchalgorithmus
Comparable
Comparable search(Comparable
search(Comparable value)
value)
{{
return
return search2(root,
search2(root, value);
value);
}}
private
private Comparable
Comparable search2(
search2(
Node
Node node,
node, Comparable
Comparable value)
value)
{{
Fall 1: Knoten ist innerer Knoten
Abhängig von Vergleich zwischen Wert
und Wegweiser links oder rechts
weitersuchen
Fall 2: Knoten ist Blatt
Wenn Wert gleich Schlüssel, dann
gefunden
Ansonsten nicht gefunden
PI-2: Bäume 2
0
18
0
1 5
0
1 2 0 1 2 0 1 2 0 3
1 1 1 1 1 1 B
Eigene Züge
((( 1 ) 3 (( 14 ) 15 )) 27 ( 39 ))
4
1
Gegnerische Züge
Universität Bremen
9
1
Gegnerische Züge
}}
5
PI-2: Bäume 2
if(node
if(node ==
== null)
null)
return
return null;
null;
else
else
{{
int
int cc == value.compareTo(node.data);
value.compareTo(node.data);
if(c
if(c << 0)
0)
return
return search2(node.left,
search2(node.left, value);
value);
else
else if(c
if(c >> 0)
0)
return
return search2(node.right,
search2(node.right, value);
value);
else
else
return
return node.data;
node.data;
}}
6
1
Universität Bremen
Universität Bremen
Suchbaum mit Wächter/Stopper
Einfügen in einen Suchbaum
Ansatz
Wie beim Suchen in Listen/Arrays mit
Wächter/Stopper
Test auf „nicht gefunden“ entfällt, da
Wert garantiert gefunden wird
Könnte in Java auch durch
Ausnahmebehandlung ersetzt
werden
Implementierung
In einem Suchbaum sind alle Blätter
identisch (ist somit eigentlich kein
Baum mehr)
In dieses einzige Blatt wird der
gesuchte Wert geschrieben
insert(17)
PI-2: Bäume 2
7
PI-2: Bäume 2
Universität Bremen
Universität Bremen
Einfügen in einen Suchbaum
Algorithmus
Suche nach dem einzufügenden
Wert, wobei selbst dann
weitergesucht wird, wenn er
gefunden wurde
Es sei denn, man will jeden Wert
nur einmal im Suchbaum
repräsentieren
Dadurch wird auf jeden Fall ein
externer Knoten gefunden
Dieser wird durch ein neues Blatt
mit dem einzufügenden Wert
ersetzt
Löschen aus einem Suchbaum
void
void insert(Comparable
insert(Comparable value)
value)
{{
if(root
if(root ==
== null)
null)
new
Node(value);
root
=
root = new Node(value);
else
else
insert2(root,
insert2(root, value);
value);
}}
private
private void
void insert2(Node
insert2(Node node,
node,
Comparable
Comparable value)
value)
{{
if(value.compareTo(node.data)
if(value.compareTo(node.data) << 0)
0)
if(node.left
==
null)
if(node.left == null)
node.left
node.left == new
new Node(value);
Node(value);
else
else
insert2(node.left,
insert2(node.left, value);
value);
else
else
if(node.right
if(node.right ==
== null)
null)
new
Node(value);
node.right
=
node.right = new Node(value);
else
else
insert2(node.right,
insert2(node.right, value);
value);
}}
PI-2: Bäume 2
9
Universität Bremen
Merke unterwegs jeweils den
Elternknoten
Wenn er gefunden wurde
Falls einer seiner Nachfolger leer
ist, ersetze ihn in seinem
Elternknoten durch den jeweils
anderen Nachfolger
Ansonsten suche den Knoten k mit
dem nächst größeren Wert,
überschreibe im zu löschenden
Knoten den Wert mit dem Wert
von k und lösche danach k
PI-2: Bäume 2
8
4
2
1
n×
3
8
5
1×
5
6
2
7
1
6
3
7
remove(4)
PI-2: Bäume 2
10
Universität Bremen
Löschen aus einem Suchbaum
Suche den zu löschenden
Knoten
8
Löschen aus einem Suchbaum
void
void remove(Comparable
remove(Comparable value)
value)
{{
remove2(root,
remove2(root, null,
null, value);
value);
}}
private
private void
void remove2(Node
remove2(Node node,
node,
Node
Node parent,
parent,
Comparable
Comparable value)
value)
{{
if(node
if(node !=
!= null)
null)
{{
int
int cc == value.compareTo(node.data);
value.compareTo(node.data);
if(c
if(c << 0)
0)
remove2(node.left,
remove2(node.left, node,
node, value);
value);
else
if(c
else if(c >> 0)
0)
remove2(node.right,
remove2(node.right, node,
node, value);
value);
else
else
removeNode(node,
removeNode(node, parent);
parent);
}}
}}
11
private
private void
void removeNode(Node
removeNode(Node node,
node,
Node
Node parent)
parent)
{{
if(node.right
==
null)
if(node.right == null)
replaceChild(parent,
node,
replaceChild(parent, node,
node.left);
node.left);
else
else if(node.left
if(node.left ==
== null)
null)
replaceChild(parent,
replaceChild(parent, node,
node,
node.right);
node.right);
else
if(node.right.left
else if(node.right.left ==
== null)
null)
{{
node.right.left
node.right.left == node.left;
node.left;
replaceChild(parent,
replaceChild(parent, node,
node,
node.right);
node.right);
}}
else
else
{{
Node
Node pon
pon == getParentOfNext(node);
getParentOfNext(node);
node.data
node.data == pon.left.data;
pon.left.data;
pon.left
pon.left == pon.left.right;
pon.left.right;
}}
}}
PI-2: Bäume 2
private
private void
void replaceChild(Node
replaceChild(Node node,
node,
Node
Node oldNode,
oldNode, Node
Node newNode)
newNode)
{{
}}
if(node
if(node ==
== null)
null)
root
root == newNode;
newNode;
else
else if(node.left
if(node.left ==
== oldNode)
oldNode)
node.left
node.left == newNode;
newNode;
else
else
node.right
node.right == newNode;
newNode;
private
private Node
Node getParentOfNext(Node
getParentOfNext(Node node)
node)
{{
node
node == node.right;
node.right;
while(node.left.left
while(node.left.left !=
!= null)
null)
node
node == node.left;
node.left;
return
return node;
node;
}}
12
2
Universität Bremen
Universität Bremen
Balancierte Bäume
Balanciertheit, Höhe, Rotieren
Motivation
Baum
Durch degenerierte Bäume kann die Suchdauer stark
ansteigen
x
Leerer Baum:
Sonst: (t1, x, t2)
AVL-Baum (Adelson-Velskij und Landis)
Definition
t1
Balanciertheit
t2
heightbal( )
= true
heightbal((t1, x, t2)) = | height(t1) - height(t2) | ≤ 1 /\ heightbal(t1) /\ heightbal(t2)
Ein Baum ist AVL-ausgeglichen oder höhenbalanciert,
wenn für jeden Knoten des Baumes gilt, dass sich die
Höhe seines linken Teilbaums von der des rechten
Teilbaums um maximal 1 unterscheidet
Höhe
height( )
=0
height((t1, x, t2)) = max(height(t1), height(t2)) + 1
Algorithmus-Idee
Jedes Einfügen oder Löschen kann die Balanciertheit des
Baumes zerstören.
Daher wird der Baum jeweils rebalanciert, sobald die
Höhen des linken und rechten Teilbaums um zwei
auseinander liegen
Baum rotieren
rotr
x
y
rotr(((t1, y, t2), x, t3)) = (t1, y, (t2, x, t3))
rotl((t1, y, (t2, x, t3))) = ((t1, y, t2), x, t3)
t1
y
t3
t1
x
t2
t2
t3
rotl
PI-2: Bäume 2
13
PI-2: Bäume 2
Universität Bremen
(Doppel-)Rotieren in AVL-Baum
Einfügen
rebal((insert(x, t1), y, t2))
falls x < y
rebal((t1, y, insert(x, t2)))
sonst
t1
Rebalancieren
t3
-
+
x 1, 0
t4
shiftl((t1, x, t2)) =
15
y
-1
t2
z
t3
t2
t4
y 1, 0
t3
t5
t4
x 0, -1
t5
t2
rotr((rotl(t1), x, t2))
rotl((t1, x, rotr(t2))) falls slope(t2) = 1
rotl((t1, x, t2))
sonst
PI-2: Bäume 2
Universität Bremen
16
Universität Bremen
Löschen aus einem AVL-Baum
B-Bäume
Löschen
Motivation
8
4
2
n×
1
AVL-Bäume eignen sich nicht gut für die Verwaltung von Daten auf Massenspeichern
(Festplatten)
Auf Daten auf Festplatten wird in Form von Sektoren zugegriffen
Der Wechsel zwischen Sektoren kostet Zeit (Kopfbewegung)
Daher: Daten linear, Baumstruktur als Index (ein Blattsuchbaum)
Index ist auch ein Baum, aber ein B-Baum, bei dem ein Knoten in einen Sektor passt
1×
3
6
5
7
Finden des nächsten Elements
leftest(( , x, t)) = (x, t)
leftest((t1, x, t2)) = (y, rebal((t, x, t2)))
wobei (y, t) = leftest(t1)
8
5
2
6
Rebalancieren eines Knotens passiert in konstanter Zeit
Bei Einfügen und Löschen wird auf dem Pfad von der
1
3
Wurzel zu einem Knoten pro Knoten einmal rebalanciert
Also ist der Aufwand O(Höhe des Baumes)
Da der Baum balanciert ist, ist der Aufwand also O(log n), auch im schlechtesten Fall
PI-2: Bäume 2
t3
z 0
x 2
t1
rotr((t1, x, t2))
PI-2: Bäume 2
Aufwand
t2
sonst
y 0
t4
-1
falls slope(t) = 2
falls slope(t) = -2
sonst
remove(x, ) =
remove(x, (t1, x, )) = t1
remove(x, ( , x, t2)) = t2
remove(x, (t1, x, t2)) = rebal(t1, y, t)
wobei (y, t) = leftest(t2)
remove(x, (t1, y, t2)) = rebal((remove(x, t1), y, t2)) falls x < y
remove(x, (t1, y, t2)) = rebal((t1, y, remove(x, t2))) falls x ≥ y
y 0, 1
+
=0
= height(t1) - height(t2)
Kann im Baum gespeichert werden und braucht
nicht immer wieder neu ausgerechnet zu werden
rebal(t) =
rotr((t1, x, t2))
x 2
Neigung eines Knotens
shiftr(t)
shiftl(t)
t
rotr((rotl(t1), x, t2)) falls slope(t1) = -1
shiftr((t1, x, t2)) =
insert(x, ) = ( , x, )
slope( )
slope((t1, x, t2))
14
Universität Bremen
Einfügen in AVL-Baum
insert(x, (t1, y, t2)) =
f((t1, x, t2)) = (t2, x, t1)
Node f(Node n) {
return new Node(n.right, n.data, n.left);}
17
7
B-Baum der Ordnung m
Alle Blätter habe die gleiche Tiefe
Jeder Knoten mit Ausnahme der Wurzel und
der Blätter hat wenigstens m/2 Kinder
Die Wurzel hat mindestens 2 Kinder
Jeder Knoten hat höchstens m Kinder
Jeder Knoten mit i Kindern hat i-1 Schlüssel
PI-2: Bäume 2
18
3
Universität Bremen
Universität Bremen
Einfügen und Suchen in B-Baum
Einfügen in einen B-Baum
Suchen
Fall 2: Übergeordneter Knoten
ist voll
Binäre Suche in den Schlüsseln eines Knotens
Dann zum nächsten Knoten, so lange, bis Blatt erreicht
Füge Schlüssel in Knoten ein (ist zu
groß)
Teile Knoten in der Mitte
Füge mittleren Knoten dem
Elternknoten hinzu
Falls dieser zu voll ist, teile ihn auch
Falls die Wurzel geteilt wird, schaffe
eine neue Wurzel und hänge die
beiden Hälften der alten Wurzel als
Nachfolger daran
Einfügen
Suche nach Einfügeposition (ein Blatt)
Fall 1: Übergeordneter Knoten ist noch nicht voll
Füge Schlüssel in Knoten ein
Erzeuge neues Blatt und referenziere dieses aus dem Knoten
insert(x)
PI-2: Bäume 2
19
PI-2: Bäume 2
20
Universität Bremen
Beispiel: Einfügen in B-Baum
insert(14)
PI-2: Bäume 2
21
4
Herunterladen