Kapitel 8 Suchverfahren

Werbung
Informatik II - 168
Kapitel 8
Suchverfahren
8.1 Laufzeitanalyse von Algorithmen und O-Notation
Die Effizienz ist ein wichtiges Kriterium zum Vergleich verschiedener Algorithmen zur Lösung
ein und desselben Problems. Sie wird bestimmt durch den benötigten Aufwand des Algorithmus
(seine Komplexität) in Abhängigkeit von einer speziellen Eingabesituation.
Wesentliche Effizienzkriterien sind
• die Laufzeit des Algorithmus
• der benötigte Speicherplatz
Häufig: ‘trade-off’ bei der Optimierung eines dieser beiden Kriterien dahingehend, daß das andere
Kriterium verschlechtert wird.
In der Regel ist das wichtigere Kriterium die Laufzeit. Wir werden uns daher im folgenden auf die
Laufzeitanalyse beschränken.
Laufzeitanalyse
1. Ansatz: Direktes Messen der Laufzeit, z.B. in Millisekunden.
➙ abhängig von vielen Parametern, wie Rechnerkonfiguration, Rechnerlast, Compiler, Betriebssystem, Programmiertricks, u.a., und damit sehr unzuverlässig und ungenau.
2. Ansatz: Zählen der benötigten Elementaroperationen des Algorithmus in Abhängigkeit von
der Größe der Eingabe.
➙ das algorithmische Verhalten wird als Funktion der benötigten Elementaroperationen dargestellt. Die Charakterisierung dieser elementaren Operationen ist abhängig von der jeweiligen Problemstellung und dem zugrundeliegenden Algorithmus. Beispiele für
Elementaroperationen sind Zuweisungen, Vergleiche, arithmetische Operationen, Zeigerdereferenzierungen oder Arrayzugriffe.
➙ das Maß für die Größe der Eingabe ist abhängig von der Problemstellung, z.B.
Problem
Größe der Eingabe
Suche eines Elementes in einer Liste
Anzahl der Elemente
Multiplikation zweier Matrizen
Dimension der Matrizen
Sortierung einer Liste von Zahlen
Anzahl der Zahlen
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 169
Betrachten wir nochmals die Laufzeit des binären Suchens. Für die Anzahl der Vergleiche im
schlechtesten Fall hatten wir ermittelt: A worst ( n ) = log 2 ( n ) + 1 .
Durch Weglassen multiplikativer und additiver Konstanten kommen wir von der Anzahl der
Schlüsselvergleiche zur Laufzeitfunktion. Damit erhält man eine von der Programmumgebung und
anderen äußeren Einflußgrößen (z.B.: dem Zeitbedarf einer Vergleichsoperation, der Effizienz der
Programmierung, ...) unabhängige Charakterisierung der (asymptotischen) Komplexität des
Algorithmus.
➙ O-Notation verwenden
Definition: O-Notation
+
+
Seien f: ( N → ℜ ) und g: ( N → ℜ ) .
f = O(g) ⇔ ∃ n 0 ∈ N , c ∈ ℜ
+
mit ∀ n ≥ n 0 ist f(n) ≤ c ⋅ g(n) .
Man sagt auch: f wächst höchstens so schnell wie g .
Anmerkung: Da O(g) genau genommen eine (unendliche) Menge von Funktionen beschreibt, ist
es genauer, zu sagen: f ∈ O(g) . In der Literatur hat sich jedoch das ‘=’ eingebürgert. Wichtig ist es, darauf zu achten, daß insbesondere die Kommutativität des ‘=’Operators hier nicht gilt.
Mit dieser Notation gilt: T worst(n) = O(Aworst(n)) .
Im Beispiel des binären Suchens also:
T worst(n) = O( log 2 ( n ) + 1) = O ( logn ) .
Funktionen, die bei der Laufzeitanalyse von Algorithmen realistischerweise auftauchen, sind meist
monoton wachsend und von 0 verschieden. Zur Überprüfung obiger Eigenschaft betrachtet man
dabei den Quotienten f(n) ⁄ g(n) .
Nach Definition gilt für f = O(g) : f(n) ⁄ g(n) ≤ c für n ≥ n 0 .
f(n)
Man betrachte den Grenzwert: lim ---------- . Existiert dieser (d.h. er ist < ∞), so ist f = O(g) .
g
n → ∞ (n)
Rechnen mit der O-Notation:
• Elimination von Konstanten:
2 ⋅ n = O(n) , n ⁄ 2 + 1 = O(n)
• Bilden oberer Schranken:
2 ⋅ n = O(n ) , 3 = O(log n)
2
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 170
Wichtige Klassen von Funktionen:
Sprechweise
Typische Algorithmen
O(1)
konstant
O(log n)
logarithmisch
Suchen auf einer Menge
O(n)
linear
Bearbeiten jedes Elementes einer Menge
O(n ⋅ log n)
Gute Sortierverfahren, z.B. Heapsort
2
O(n ⋅ log n)
...
2
O(n )
k
O(n ), k ≥ 2
quadratisch
primitive Sortierverfahren
polynomiell
...
n
O(2 )
exponentiell
Backtracking-Algorithmen
Nach diesem Exkurs in die O-Notation wollen wir uns nochmals Bäumen zuwenden, diesmal nicht
beschränkt auf binäre Bäume.
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 171
8.2 Baumstrukturen
Ein Baum ist eine endliche Menge T von Elementen, Knoten genannt, mit:
(1) Es gibt einen ausgezeichneten Knoten w(T) , die Wurzel von T
(2) Die restlichen Knoten sind in m ≥ 0 disjunkte Mengen T1, …, Tm zerlegt, die ihrerseits
Bäume sind. T1, …, Tm heißen Teilbäume der Wurzel w(T) . (rekursive Definition)
T
w(T)
T2
T1
… Tm
Eine lineare Liste ist ein (entarteter) Baum, in dem jeder Knoten höchstens einen Teilbaum besitzt.
Bäume erlauben es, hierarchische Beziehungen zwischen Objekten darzustellen. Derartige
Hierarchien treten vielfach in der realen Welt auf, z.B.:
• Die Strukturierung eines Unternehmens in Bereiche, Abteilungen, Gruppen und Angestellte
Unternehmen
Bereich 3
Abteilung 1
Gruppe 1
Müller
Meier
Kuhn
Schmidt
• Die Gliederung eines Buches in Kapitel, Abschnitte, Unterabschnitte
• Die Aufteilung Deutschlands in Bundesländer, Bezirke, Kreise, Gemeinden
• Darstellung (geklammerter) arithmetischer Ausdrücke als binäre Bäume (d.h. m ≤ 2 für alle
Knoten des Baumes). Diese Bäume heißen Operatorbäume.
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 172
Operatorbaum für: a - b * (c / d + e / f)
a
*
+
b
/
c
/
d
e
f
Der Grad eines Knotens x, deg(x), ist gleich der Anzahl der Teilbäume von x. Gilt deg(x) = 0, so
nennt man x ein Blatt.
Der Grad des Baumes ist der maximale Grad aller seiner Knoten.
Jeder Knoten x ≠ w(T) hat einen eindeutigen Vorgänger v(x), auch Vater von x genannt. s(x) bezeichnet die Menge aller Söhne (auch Kinder oder Nachfolger von x genannt) und b(x) die Menge
aller Brüder von x (auch Geschwister von x genannt). Alle Brüder in b(x) haben denselben Vater
wie x.
Ein Pfad in einem Baum ist eine Folge von Knoten p1, …, pn mit: pi = v(pi+1), i = 1, …, n-1. Die
Länge des Pfades ist n.
1
für x = w(T)

Der Level eines Knotens x, lev(x) ist: lev(x) = 
.
für x ≠ w(T)
 lev(v(x)) + 1
Damit ist lev(x) gleich der Anzahl der Knoten auf dem Pfad von der Wurzel zum Knoten x.
Die Höhe eines Baumes ist gleich dem maximalen Level seiner Knoten. Dies entspricht der Länge
des längsten von der Wurzel ausgehenden Pfades innerhalb des Baumes.
Ein Wald ist eine geordnete Menge von n ≥ 0 disjunkten Bäumen. Entfernt man die Wurzel eines
Baumes, so erhält man einen Wald.
Ein binärer Baum ist eine endliche Menge B von Knoten, die
• entweder leer ist
• oder aus einer Wurzel und zwei disjunkten binären Bäumen besteht, dem linken und dem rechten Teilbaum der Wurzel.
A
Damit sind:
B
und
A
zwei verschiedene binäre Bäume, aber als Bäume gleich.
B
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 173
Suchverfahren
Gegeben sei eine Menge von Objekten, die durch (eindeutige) Schlüssel charakterisiert sind. Aufgabe von Suchverfahren ist die Suche bestimmter Objekte anhand ihres Schlüssels.
Bisher: zwei Methoden der Speicherung solcher Objekte
• sequentielle Speicherung ➙ sortiertes Array (binäre Suche)
• verkettete Speicherung
➙ lineare Liste
Zeitaufwand im schlechtesten Fall für eine Menge von n Elementen;
Operation
sequentiell gespeichert
(sortiertes ARRAY)
verkettet gespeichert
(lineare Liste)
Suche Objekt mit gegebenem Schlüssel
O(log n)
O(n)
Einfügen an bekannter Stelle
O(n)
O(1)
Entfernen an bekannter Stelle
O(n)
O(1)
Im folgenden werden wir Verfahren behandeln, die sowohl die Suche als auch das Einfügen und
Entfernen “effizient” unterstützen (bessere Laufzeitkomplexität als O(n)).
8.3 Binäre Suchbäume
Ziel: Die Operationen Suchen, Einfügen und Entfernen sollen alle in O(log n) Zeit durchgeführt
werden.
Ansatz: Organisation der Objektmenge als Knoten eines binären Baumes.
Definition:
Ein binärer Baum heißt binärer Suchbaum, wenn für jeden seiner Knoten die Suchbaumeigenschaft gilt, d.h. alle Schlüssel im linken Teilbaum sind kleiner, alle Schlüssel im rechten Teilbaum sind größer als der Schlüssel im Knoten:
k
<k
>k
linker Teilbaum
rechter Teilbaum
Tl
Tr
Anmerkungen:
• Zur Organisation einer gegebenen Menge von n Schlüsseln gibt es eine große Anzahl
unterschiedlicher binärer Suchbäume.
• Der inorder-Durchlauf eines binären Suchbaumes generiert die (aufsteigend) sortierte
Folge der gespeicherten Schlüssel.
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 174
Beispiele:
Zwei verschiedene binäre Suchbäume über den Monatsnamen:
DEZ
JAN
AUG
FEB
NOV
MÄR
APR
APR
MAI
AUG
JUN
DEZ
JUL
SEP
JUL
OKT
FEB
OKT
JUN
SEP
MAI
JAN
MÄR
NOV
Der Entscheidungsbaum zur binären Suche ist ein binärer Suchbaum:
17
8
23
5
11
3
0
7
1
2
9
3
4
19
13
5
6
18
7
8
27
21
9
24
30
10 11 12 13 14 31
15 16
8.3.1 Allgemeine binäre Suchbäume
class BinaryNode
{
int key;
BinaryNode left;
BinaryNode right;
BinaryNode(int k) { key=k; left = null; right = null;}
}
public class BinarySearchTree
{
BinaryNode root;
public BinarySearchTree () { root = null; }
// ... Implementierung der Methoden insert, find, delete,...
}
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 175
Die Methode insert (int x) der Klasse BinarySearchTree fügt einen gegebenen Schlüssel x ein, falls
dieser noch nicht im Baum enthalten ist:
// Methoden der Klasse BinarySearchTree
public void insert (int x) throws Exception
{ root = insert (x, root);}
protected BinaryNode insert (int x, BinaryNode t) throws Exception
{ if ( t == null) t = new BinaryNode (x);
else if (x < t.key)
t.left = insert (x, t.left);
else if (x > t.key)
t.right = insert (x, t.right);
else
throw new Exception (“Inserting twice”);
return t;
}
Die überladene interne Methode insert (x, t) liefert eine Referenz auf die Wurzel des Teilbaums
zurück, in den x eingefügt wurde.
Die folgende Methode find (x) sucht in einem binären Suchbaum den Schlüssel x und liefert diesen
zurück, falls er gefunden wurde. Andernfalls wird eine Ausnahmebehandlung durchgeführt.
// Methoden der Klasse BinarySearchTree
public int find (int x) throws Exception
{ return find (x, root).key;}
protected BinaryNode find (int x, BinaryNode t) throws Exception
{ while ( t != null)
{if ( x < t.key) t = t.left;
else if ( x > t.key) t = t.right;
else
return t;
// Match
}
throw new Exception (“key not found”);
}
Das Entfernen eines Schlüssels ist etwas komplexer, da auch Schlüssel in inneren Knoten des
Baumes betroffen sein können und die Suchbaumstruktur aufrecht erhalten werden muß.
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 176
Hierzu zunächst ein Beispiel:
7
3
19
7
14
3
14 entfernen
33
19
33
19
3
7 entfernen
33
19
52
3
52
33
26
52
26
26
52
19
26
Allgemein treten zwei grundsätzlich verschiedene Situationen auf:
Fall 1: der Knoten q mit dem zu entfernenden Schlüssel besitzt höchstens einen Sohn (Blatt
oder Halbblatt)
Fall 2: der Knoten q mit dem zu entfernenden Schlüssel besitzt zwei Söhne (innerer Knoten)
Fall 1:
a) der Knoten q besitzt
keinen Sohn
p
b) der Knoten q besitzt
einen linken Sohn (rechts➙symmetrisch)
p
p
q
p
q
null
null
null
null
p.right = q.left;
p.right = null;
Fall 2:
p
p
q
s
Programmcode:
s. Methode‘deleteMin’
T1
T1
r
r
s
T3
T2
null
T3
T2
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 177
Die folgende Methode delete(x) entfernt einen Schüssel x aus einem binären Suchbaum. Hierbei
wird eine Hilfsmethode findMin verwendet, die den Knoten des kleinsten Schlüssels des rechten
Teilbaumes (eines inneren Knotens) bestimmt und eine weitere Hilfsmethode deleteMin, die diesen
Knoten entfernt:
// Methoden der Klasse BinarySearchTree
public void delete(int x) throws Exception
{ root = delete (x, root);}
protected BinaryNode delete (int x, BinaryNode t) throws Exception
{ if (t == null)
throw new Exception (“x does not exist (delete)”);
if (x < t.key) t.left = delete (x, t.left);
else if (x > t.key) t.right = delete (x, t.right);
else if (t.left != null && t.right != null)// x is in inner node t
{ t.key = findMin (t.right).key;
t.right = deleteMin (t.right);
}
else // x is in leaf or in semi-leaf node, reroot t
t = (t.left != null) ? t.left : t.right;
return t;
}
protected BinaryNode findMin (BinaryNode t) throws Exception
{ if ( t == null)
throw new Exception (“key not found (findMin)”);
while ( t.left != null) t = t.left;
return t;
}
protected BinaryNode deleteMin (BinaryNode t) throws Exception
{ if (t == null)
throw new Exception (“key not found (deleteMin)”);
if (t.left != null)
t.left = deleteMin (t.left);
else
t = t.right;
return t;
}
Zum Verständnis: Der Fall des Entfernens aus einem inneren Knoten (t.right != null &&
t.left != null) wird auf eine ‘Blatt-’ (t.right == null && t.left == null) oder eine ‘HalbblattSituation’ (t.right != null || t.left != null) zurückgeführt, indem der zu löschende Schlüssel
durch den kleinsten der größeren Schlüssel ersetzt wird. Dieser Schlüssel befindet sich stets
in einem Blatt oder einem Halbblatt, das daraufhin aus dem Baum entfernt wird.
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 178
Laufzeitanalyse der Algorithmen insert, find und delete
Alle drei Methoden sind auf einen einzigen, bei der Wurzel beginnenden Pfad des Suchbaumes beschränkt.
➙ der maximale Aufwand ist damit O(h) , wobei h die Höhe des Baumes ist.
Für die Höhe binärer Bäume mit n Knoten gilt:
• Die maximale Höhe eines binären Baumes mit n Knoten ist n. (➙ Lineare Liste)
• Seine minimale Höhe ist log2(n+1)
Begründung: Für eine gegebene Anzahl n von Knoten haben die sogenannten vollständig
ausgeglichenen binären Bäume minimale Höhe. In einem vollständig ausgeglichenen binären Baum müssen alle Levels bis auf das unterste vollständig
besetzt sein. Die maximale Anzahl n von Knoten in einem vollständig
h–1
ausgeglichenen binären Baum der Höhe h ist:
i
h
n = ∑2 = 2 –1
i=0
➙ h min =
log2(n + 1) .
Bemerkung: Es gilt: log 2(n + 1)
=
log 2(n) + 1 ∀n ∈ IN .
Eine aufwendige Durchschnittsanalyse ergibt unter den beiden Annahmen:
• der Baum ist nur durch Einfügungen entstanden und
• alle möglichen Permutationen der Eingabereihenfolge sind gleichwahrscheinlich
einen mittleren Wert h ∅ = 2 ⋅ ln 2 ⋅ log n ≈ 1,386 ⋅ log n .
Der durchschnittliche Zeitbedarf für Suchen, Einfügen und Entfernen ist damit O(log n) .
Kritikpunkt am naiven Algorithmus zum Aufbau binärer Suchbäume und damit an der Klasse so
erzeugter binärer Suchbäume:
➙ im worst-case ist der Aufwand aller drei Operationen O(n) .
8.3.2 Vollständig ausgeglichene binäre Suchbäume
Die minimale Höhe log 2(n + 1) unter allen binären Suchbäumen besitzen die vollständig ausgeglichenen binären Suchbäume, d.h. binäre Suchbäume, bei denen alle Levels bis auf das unterste vollständig besetzt sind.
➙ optimaler Zeitaufwand für Suchoperationen
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 179
Vollständig ausgeglichene binäre Bäume für verschiedene Knotenzahlen n:
n=1
n=3
n=2
n=4
n=6
n=5
n=7
Level 1
n = 13
2
Höhe 4
3
4
Beispiel: Einfügen von Schlüssel ‘B’ in einen bestehenden Baum
E
D
C
A
G
D
F
B
A
F
C
E
G
B
Problem: Der Baum muß beim Einfügen von B vollständig reorganisiert werden.
➙ Einfügezeit im schlechtesten Fall: O(n) .
➙ Auswahl einer Kompromißlösung mit den Eigenschaften:
• die Höhe des Baumes ist im schlechtesten Fall O(log n) .
• Reorganisationen bleiben auf den Suchpfad zum einzufügenden bzw.. zu entfernenden
Schlüssel beschränkt und sind damit im schlechtesten Fall in O(log n) Zeit ausführbar.
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 180
Definition:
Eine Klasse von Suchbäumen heißt balanciert, falls:
• h max = O(log n)
• die Operationen Suchen, Einfügen und Entfernen sind auf einen Pfad von der Wurzel zu
einem Blatt beschränkt und benötigen damit im schlechtesten Fall O(log n) Zeit.
Klasse der Suchbäume
Klasse balancierter Suchbäume
Klasse der vollständig ausgeglichenen
Suchbäume (Höhe = log2 (n+1))
8.3.3 AVL-Bäume
(Adelson-Velskij und Landis (1962))
AVL-Bäume sind ein Beispiel für eine Klasse balancierter Suchbäume.
Definition:
Ein binärer Suchbaum heißt AVL-Baum, falls für die beiden Teilbäume Tr und Tl der Wurzel
gilt:
• h(T r) – h(T l) ≤ 1
• Tr und Tl sind ihrerseits AVL-Bäume. (rekursive Definition)
Der Wert h(T r) – h(T l) wird als Balancefaktor (BF) eines Knotens bezeichnet. Er kann in
einem AVL-Baum nur die Werte -1, 0 oder 1 (dargestellt durch -, = und +) annehmen.
Mögliche Strukturverletzungen durch Einfügungen bzw. Entfernungen von Schlüsseln erfordern Rebalancierungsoperationen.
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 181
Beispiel für einen AVL-Baum:
- L
N
I
+
E
B
C
=
P
=
G
=
O
K
-
=
A
=
M
J
+
=
=
R
=
=
= F
Behauptung: Die minimale Höhe h min(n) eines AVL-Baumes mit n Schlüsseln ist log 2(n + 1) .
Dies folgt aus der Tatsache, daß ein AVL-Baum minimaler Höhe einem vollständig
ausgeglichenen binären Suchbaum entspricht.
Behauptung: Die maximale Höhe h max(n) eines AVL-Baumes mit n Schlüsseln ist O(log n) .
Beweis:
Die maximale Höhe wird realisiert von sogenannten minimalen AVL-Bäumen. Dies
sind AVL-Bäume, die für eine gegebene Höhe h die minimale Anzahl von Schlüsseln abspeichern.
Minimale AVL-Bäume haben bis auf Symmetrie die folgende Gestalt:
nh-1
nh-2
Sei nh die minimale Anzahl von Schlüsseln in einem AVL-Baum der Höhe h.
Dann gilt: n h = n h – 1 + n h – 2 + 1 für h ≥ 2 und n 0 = 0 , n 1 = 1 .
Die minimalen AVL-Bäume der Höhen h = 0, 1, 2, 3, 4 haben bis auf Symmetrie
folgende Gestalt:
Die Rekursionsgleichung für n h erinnert an die Definition der Fibonacci-Zahlen:
n

fib(n) = 
 fib(n-1) + fib(n-2)
Universität München, Institut für Informatik, Hans-Peter Kriegel
für n ≤ 1
für n > 1
Studienjahr 2002
Informatik II - 182
h
0
1
2
3
4
5
6
nh
0
1
2
4
7
12
20
fib(h)
0
1
1
2
3
5
8
Hypothese: n h = fib(h + 2) – 1
Beweis: Induktion über h
Induktionsanfang: n 0 = fib(2) – 1 = 1 – 1 = 0
✓
Induktionsschluß: n h + 1 = n h + n h – 1 + 1
= 1 + fib(h + 2) – 1 + fib(h + 1) – 1
= fib(h + 3) – 1
1
1+ 5
1– 5
n
n
Hilfssatz: fib(n) = ------- ⋅ ( ϕ 1 – ϕ 2 ) mit ϕ 1 = ----------------, ϕ 2 = ---------------- ≈ – 0,618 .
2
2
5
Der Beweis erfolgt durch vollständige Induktion. (wird hier übergangen)
Für jede beliebige Schlüsselanzahl n ∈ IN gibt es ein eindeutiges h max(n) mit:
n hmax(n) ≤ n < n hmax(n) + 1 .
Mit obiger Hypothese folgt hieraus: n + 1 ≥ fib(h max(n) + 2) .
Durch Einsetzen erhalten wir:

h (n) + 2 1
1
 ≥ ------ ⋅ ϕ 1 max
– --ϕ2

2
5
< 0,62 < 5 ⁄ 2
h max(n) + 2






1  h max(n) + 2
n + 1 ≥ ------- ⋅  ϕ 1
–
5 
h (n) + 2
1
3
Und damit: ------- ⋅ ϕ 1 max
≤ n + --- .
2
5
1
3
Durch Auflösen nach h max(n) ergibt sich: log ϕ1(-------) + h max(n) + 2 ≤ log ϕ1(n + ---) .
2
5
Und für h max(n) :
3
1
hmax(n) ≤ log ϕ1(n + ---) –  log ϕ1(-------) + 2 ≤
2
5
≤ log ϕ1(n) + const = log ϕ1(2) ⋅ log 2(n) + const
c(a)
 log (a) = log
---------------b

logc(b)
ln 2
= ----------- ⋅ log 2(n) + const ≈ 1,44 ⋅ log 2(n) + const
ln ϕ 1
Für große Schlüsselanzahlen ist die Höhe eines AVL-Baumes somit um maximal
44% größer als die des vollständig ausgeglichenen binären Suchbaumes.
Also gilt die Behauptung: h max(n) = O(log n) .
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 183
Einfügen von Schlüsseln: Insert(k)
(In der folgenden Beschreibung sind symmetrische Fälle nicht dargestellt.)
Der Schlüssel k wird in einen neuen Sohn K des Knotens B eingefügt.
Fall 1: B ist ein Blatt
B
B +*
=
K = *
und UP(B)
K =
Fall 2: B hat einen linken Sohn
B
B
-
=
STOP
A
=
K
=
*
A
=
K
=
Die Methode UP(S) wird aufgerufen für einen Knoten S, dessen Teilbaum in seiner Höhe um 1
gewachsen ist. S ist die Wurzel eines korrekten AVL-Baumes.
➙ mögliche Strukturverletzung durch einen zu hohen Teilbaum!
S
Fall 1: der Vater von S hat BF ‘= ‘
1.1 der Vater von S ist nicht die Wurzel
A +*
A =
S *
S
und UP(A)
1.2 der Vater von S ist die Wurzel: ➙ dieselbe Transformation und STOP.
Fall 2: der Vater von S hat BF ‘+’ oder ‘-’ und S ist die Wurzel des kürzeren Teilbaumes.
➙ In beiden Fällen wird der BF im Vater zu ‘=’ und STOP.
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 184
Fall 3: der Vater von S hat BF ‘+’ oder ‘-’ und S ist die Wurzel des höheren Teilbaumes.
3.1 der Vater von S hat BF ‘+’ und S hat BF ‘+’:
A +
S +
T1
S =
*
A=
T1
T2
T2
T3
STOP
T3
Rotation
3.2 der Vater von S hat BF ‘+’ und S hat BF ‘-’.
z.B.: B hat BF ‘-’.
A +
S -
T1
B =
*
A=
B -
T1
T2
+S
T3
STOP
T4
T4
T3
T2
Doppel-Rotation
der Fall B hat BF ‘+’ wird analog gehandhabt.
3.3 der Vater von S hat BF ‘-’ und S hat BF ‘-’: ➙ symmetrisch zu 3.1
3.4 der Vater von S hat BF ‘-’ und S hat BF ‘+’: ➙ symmetrisch zu 3.2
Beim Einfügen genügt eine einzige Rotation bzw. Doppelrotation um eine Strukturverletzung zu
beseitigen. Wir werden sehen, daß dies beim Entfernen nicht genügt.
Entfernen von Schlüsseln: Delete(k)
(In der folgenden Beschreibung sind symmetrische Fälle nicht dargestellt.)
Der Knoten K mit Schlüssel k wird entfernt.
Fall 1: K hat höchstens einen Sohn
1.1 K ist ein Blatt
1.1.1 K hat keinen Bruder
B
K
-
B
= *
Universität München, Institut für Informatik, Hans-Peter Kriegel
=
* und UP’(B)
Studienjahr 2002
Informatik II - 185
1.1.2 K hat einen Bruder
B =
K = *
A =
oder
B STOP
A =
D K = *
B =
A =
C -
C =
oder
B -
D =
STOP
A =
D -
C =
K = *
B +
B =
D =
und UP’(C)
C =
B = *
C -
oder
K = *
B -
A =
C =
und UP’(B)
A =
1.2 K hat genau einen Sohn
1.2.1 K hat einen linken Sohn
K
B
- *
B
=
=
* und UP’(B)
1.2.2 K hat einen rechten Sohn: ➙ symmetrisch
Fall 2: K ist ein innerer Knoten (hat zwei Söhne)
Man bestimme in dem AVL-Baum den kleinsten Schlüssel s, der größer als k ist.
s ist in einem Halbblatt S. Ersetze k durch s und entferne den Schlüssel s.
➙ damit haben wir Fall 2 auf Fall 1 zurückgeführt.
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 186
Die Methode UP’(S) wird aufgerufen für einen Knoten S, dessen Teilbaum in seiner Höhe um 1
reduziert ist. Der Teilbaum mit Wurzel S ist ein korrekter AVL-Baum.
➙ mögliche Strukturverletzung durch einen zu niedrigen Teilbaum!
S
*
Fall 1: der Vater von S hat BF ‘=’.
B -
B=
*
S
S
STOP
Fall 2: der Vater von S hat BF ‘+’ oder ‘-’ und S ist die Wurzel des höheren Teilbaums.
B =*
B+
S
*
S
und UP’(B)
Fall 3: der Vater von S hat BF ‘+’ oder ‘-’ und S ist die Wurzel des kürzeren Teilbaums.
3.1 der Vater von S hat BF ‘+’
3.1.1 der Bruder von S hat BF ‘=’
U+
S
V U+
V =
*
T2
S
T1
STOP
T1
T2
Rotation
3.1.2 der Bruder von S hat BF’+’.
V =*
U+
U=
V +
S *
S
T1
T2
und UP’(V)
T1
T2
Rotation
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 187
3.1.3 der Bruder von S hat BF’-’.
V =*
U +
S
U
W -
*
V
W
S
und UP’(V)
T1
T2
T3
T3
T1
T2
Doppel-Rotation
Mindestens einer der beiden Bäume T1 und T2 hat die durch den hell schraffierten
Bereich angegebene Höhe.
3.2 der Vater von S hat BF ‘-’: ➙ symmetrisch zu 3.1.
Fall 4: S ist die Wurzel. ➙ STOP
Im Falle von Entferne-Operationen wird eine mögliche Strukturverletzung also nicht
notwendigerweise durch eine einzige Rotation bzw. Doppelrotation beseitigt. Im schlechtesten Fall
muß auf dem Suchpfad bottom-up vom zu entfernenden Schlüssel bis zur Wurzel auf jedem Level
eine Rotation bzw. Doppelrotation durchgeführt werden.
Korollar: Die AVL-Bäume bilden eine Klasse balancierter Bäume.
8.4 B-Bäume
Sei n die Anzahl der Objekte und damit der Datensätze. Wir nehmen nun an, daß das Datenvolumen zu groß ist, um im Hauptspeicher gehalten zu werden, z.B. n = 106.
➙ Datensätze auf externen Speicher auslagern, z.B. Plattenspeicher.
Beobachtung: Der Plattenspeicher wird als Menge von Blöcken (mit einer Größe im Bereich von
1 - 4 KByte) betrachtet, wobei ein Block durch das Betriebssystem jeweils
komplett in den Hauptspeicher übertragen wird. Diese Übertragungseinheiten werden auch als Seiten des Plattenspeichers bezeichnet.
Idee: Konstruiere eine Baumstruktur mit der Eigenschaft:
^ 1 Seite (bzw. mehreren Seiten) des Plattenspeichers
1 Knoten des Baumes =
Für binäre Baumstrukturen bedeutet das:
^ 1 Plattenspeicherzugriff
left oder right-Zeiger folgen =
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 188
Beispiel:
Sei die Anzahl der Datensätze: n = 106
6
3 2
3
➙ log 2(10 ) = log2(10 ) = 2 ⋅ log2(10 ) ≈ 20 Plattenspeicherzugriffe
Idee: Zusammenfasssen mehrerer binärer Knoten zu einer Seite
Übertragungseinheit
(“Seite”)
enthält hier 7 Knoten
Beispiel für einen B-Baum:
99 Knoten in einer Seite ➙ 100-fache Verzweigung:
6
➙ log 100(10 ) = 3 Plattenspeicherzugriffe.
(reduziert auf 2, falls die Wurzelseite immer im Hauptspeicher liegt)
Definition: B-Baum der Ordnung m (Bayer und McCreight (1972))
(1) Jeder Knoten enthält höchstens 2m Schlüssel.
(2) Jeder Knoten außer der Wurzel enthält mindestens m Schlüssel.
(3) Die Wurzel enthält mindestens einen Schlüssel.
(4) Ein Knoten mit k Schlüsseln hat genau k+1 Söhne.
(5) Alle Blätter befinden sich auf demselben Level.
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 189
Beispiel: für einen B-Baum der Ordnung 2
K
C F
A B
O T
D E
G I J
L M
P Q RS
V WX Z
Berechnung der maximalen Höhe h max eines B-Baumes der Ordnung m mit n Schlüsseln:
Level 1 hat
k1 = 1 Knoten
Level 2 hat
k2 ≥ 2 Knoten
Level 3 hat
k3≥ 2(m+1) Knoten
.
.
Level h+1 hat
.
.
kh+1 ≥ 2(m+1)h-1 (äußere, leere) Knoten
Ein B-Baum mit n Schlüsseln teilt den Wertebereich der Schlüssel in n + 1 Intervalle. Es gilt also
n+1
kh+1 = n + 1 ≥ 2(m+1)h-1, d.h. h ≤ 1 + log m + 1  ------------ .
 2 
Da die Höhe immer ganzzahlig ist, und da diese Rechnung minimalen Füllgrad annimt, folgt:
n+1
h ≤ log m + 1  ------------ + 1
 2 
Beobachtung: Jeder Knoten (außer der Wurzel) ist mindestens mit der Hälfte der möglichen
Schlüssel gefüllt. Die Speicherplatzausnutzung beträgt also mindestens 50 %!
Allgemeine Knotenstruktur:
p0, k 1,p1 , k2, . . . . ,pj-1 , kj, pj
wobei: k 1 < k 2 < … < k j und m ≤ j ≤ 2m ;
pi zeigt auf den Teilbaum mit Schlüsseln zwischen k i und k i + 1 .
pi
ki < Schlüssel < ki+1
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 190
Anmerkung: Da die Schlüssel in jedem Knoten eines B-Baumes aufsteigend sortiert sind, kann
ein Knoten nach Übertragung in den Hauptspeicher binär durchsucht werden.
class Entry { public int key;
public Page son;
... // Konstruktor..
}
class Page { public int numberOfEntries;
public Page firstSon;
public Entry [] entries;
// Im Konstruktor intialisieren mit new Entry [2*m+1];
...
}
class Btree { protected Page root;
protected int m;
...
}
Welche Ordnung m von B-Bäumen ist auf realen Rechnern und Plattenspeichern günstig?
Hierzu betrachten wir zunächst den physischen Aufbau eines Magnetplattenspeichers. Dieser
besteht aus einer Reihe übereinanderliegender rotierender Magnetplatten, die in Zylinder,
Spuren und Sektoren unterteilt sind. Der Zugriff erfolgt über einen Kamm mit Schreib-/Leseköpfen, der quer zur Rotation bewegt wird.
Kammbewegung
Spur
Kamm
Zylinder
SchreibLesekopf
Rotation
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 191
Der Seitenzugriff erfolgt nun in mehreren Phasen. Etwas vereinfacht läßt sich die Zugriffszeit
in die Zeiten für die folgenden Phasen zerlegen:
• Positionierung des Schreib-/Lesekopfes: Positionierungszeit (PZ)
Zeit für die Kammbewegung
6 ms
• Warten auf den Sektor / die Seite: Latenzzeit (LZ)
Im Mittel halbe Rotationszeit der Platte
4 ms
• Übertragung der Seite: Übertragungszeit (ÜZ)
Zeit für das Schreiben / Lesen
1·10-4 ms / Byte
➙ Zugriffszeit für eine Seite: PZ + LZ + ÜZ · (Seitengröße).
Sei die Größe eines Schlüssels durch α Bytes und die eines Zeigers durch β Bytes gegeben.
➙ Seitengröße ≈ 2m ( α + β )
≈ 2m ( α + β ) = a + b·m
mit: a = PZ + LZ und b = 2(α+β) · ÜZ.
➙ Zugriffszeit pro Seite = PZ + LZ + ÜZ ·
Andererseits ergibt sich für die interne Verarbeitungszeit pro Seite bei binärer Suche:
c ⋅ log 2(m) + d für Konstanten c und d.
Die gesamte Verarbeitungszeit pro Seite ist damit: a + b ⋅ m + c ⋅ log 2(m) + d .
Die maximale Anzahl von Seiten auf einem Suchpfad eines B-Baumes mit n Schlüsseln ist:
hmax =
n+1
log 2(------------)
n+1
2
log m + 1(------------) + 1 = f ⋅ -------------------------- für eine Konstante f.
2
log 2(m)
Die maximale Suchzeit MS ist damit gegeben durch die Funktion:
a+d
b⋅m
n+1
MS(m) = g ⋅  ------------------ + ------------------ + c mit g = f ⋅ log 2(------------) .
log 2(m) log 2(m)
2
Für die obigen Konstanten setzen wir beispielhaft die folgenden Werte ein:
a = 0,01s, a + d ≈ a = 0,01s . = 10 ms
–4
–4
α = 8, β = 4 ➙ b = 24 ⋅ 1 ⋅ 10 ms = 24 ⋅ 10 ms .
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 192
Damit ist die folgende Funktion MS(m) zu minimieren:
10
0,0024 ⋅ m
MS(m) =  ------------------ + ------------------------- ms ➙ MIN.
log 2(m)
log2(m)
MS(m)
1.5
1.25
600
750
m
900
Die maximale Suchzeit ist somit nahezu minimal für 600 ≤ m ≤ 900 . Dies entpricht in obigem
Beispiel einer “optimalen” Seitengröße von 12 KByte.
Einfügen in B-Bäumen:
Zunächst wird der Knoten K gesucht, in den der neue Schlüssel einzufügen ist. Dieser ist stets ein
Blatt. Der Schlüssel wird in K an der entsprechenden Stelle eingefügt.
Sei s die Anzahl der Schlüsel in K nach dem Einfügen:
Fall 1:
s ≤ 2m :
Fall 2:
s = 2m + 1 : ➙ OVERFLOW
➙ STOP
Ein OVERFLOW wird behandelt durch Aufspalten (SPLIT) des Knotens.
Dies kann einen OVERFLOW im Vaterknoten zur Folge haben. Auf diese Weise kann sich
ein OVERFLOW bis zur Wurzel des Baumes fortsetzen.
Falls die Wurzel gesplittet wird wächst die Höhe des Baumes um 1.
möglicher OVERFLOW
im Vaterknoten
SPLIT:
km+1
*
k1 k2 k3
...
k2m+1
k1 k2
...
Universität München, Institut für Informatik, Hans-Peter Kriegel
km
km+2 . . .
k2m+1
Studienjahr 2002
Informatik II - 193
Entfernen aus B-Bäumen:
Der zu entfernende Schlüssel k wird im Baum gesucht und aus dem gefundenen
Knoten K gelöscht. Falls K kein Blatt ist, wird der entfernte Schlüssel durch den
Schlüssel p ersetzt, der der kleinste Schlüssel im Baum ist, der größer als k ist. Sei P
der Knoten, in dem p liegt. Dann ist P ein Blatt, aus dem p nun entfernt wird. Auf diese
Weise wird der Fall “Löschen in einem inneren Knoten” auf den Fall “Löschen in
einem Blatt” zurückgeführt.
Sei s die Anzahl der Schlüssel in K nach dem Entfernen:
Fall 1: s ≥ m :
➙ STOP
Fall 2: s = m – 1 : ➙ UNDERFLOW
UNDERFLOW-Behandlung:
Fall 1: Der Bruder hat ≥ m+1 Schlüssel: ➙ Ausgleichen mit dem Bruder
#=r
#=r
k
l
STOP
*
#=m-1
l
#=m k
#=b-1
# = b (>m)
Fall 2: Der Bruder hat m Schlüssel: ➙ Verschmelzen mit dem Bruder unter Hinzunahme
des trennenden Vaterschlüssels
➙ möglicher UNDERFLOW im Vaterknoten.
# = r - 1 möglicher
UNDERFLOW
im Vaterknoten
#=r
k
*
#=m-1
#=m
#=m-1 k
#=m
# = 2m
So kann sich auch die UNDERFLOW-Behandlung bis zur Wurzel des Baumes fortsetzen.
Wird aus der Wurzel des Baumes der letzte Schlüssel entfernt, so wird diese gelöscht; die Höhe des
Baumes verringert sich damit um 1.
Korollar: Die B-Bäume bilden eine Klasse balancierter Suchbäume.
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Informatik II - 194
Aufwandsabschätzung für die durchschn. Anzahl von Aufspaltungen (Splits) pro Einfügung:
Bezeichne s die durchschnittliche Anzahl der Knoten-Splits pro Einfügung:
Modell:
Ausgehend von einem leeren Baum wird ein B-Baum der Ordnung m für die Schlüssel
k 1, k 2, …, k n durch n aufeinanderfolgende Einfügungen konstruiert.
Sei t die Gesamtzahl der Aufspaltungen bei der Konstruktion dieses B-Baumes
➙s = t ⁄ n.
Sei p die Anzahl der Knoten (Seiten) des B-Baumes mit p ≥ 3
➙ t < p – 1 (genauer: t ≤ p – 2 )
Für die Anzahl n der Schlüssel in einem B-Baum der Ordnung m mit p Knoten gilt:
n ≥ 1 + (p – 1) ⋅ m .
t p –1 1 n–1 1
n –1
➙ p – 1 ≤ --------- ➙s = --- < --------- ≤ --- ⋅ --------- < ---- wobei im allg.: 600 ≤ m ≤ 900 (s.o.).
m
n
n
n m
m
Es gilt: t ≤ p - 2 ➙ t < p - 1 für p ≥ 3
Denn:
- bei jeder Aufspaltung wird mindestens ein zusätzlicher Knoten geschaffen
- Aufspalten der Wurzel ➙ 2 zusätzliche Knoten
- wenn ein B-Baum mehr als einen Knoten hat, dann ist die Wurzel mindestens einmal
aufgespalten worden
- dem ersten Knoten des B-Baums geht keine Aufspaltung voraus.
Universität München, Institut für Informatik, Hans-Peter Kriegel
Studienjahr 2002
Herunterladen