Grundlagen der Algorithmen und Datenstrukturen

Werbung
Grundlagen der Algorithmen
und Datenstrukturen
Kapitel 7
Christian Scheideler + Helmut Seidl
SS 2009
27.05.09
Kapitel 7
1
Wörterbuch
S: Menge von Elementen
Jedes Element e identifiziert über e.key().
Operationen:
• S.insert(Element e): S = S [ {e};
• S.removeKey(Key k): S = Sn{e}; wobei e das
Element ist mit e.key()==k
• S.find(Key k): Falls es ein e2 S gibt mit
e.key()==k, dann gib e aus, sonst gib ? aus
27.05.09
Kapitel 7
2
Suchstruktur
S: Menge von Elementen
Jedes Element e identifiziert über key(e).
Operationen:
• S.insert(Element e): S = S [ {e};
• S.removeKey(Key k): S = Sn{e}; wobei e
das Element ist mit e.key()==k
• S.locate(Key k): gib e2 S aus mit
minimalem e.key() so dass e.key() ≥ k
27.05.09
Kapitel 7
3
Wörterbuch vs. Suchstruktur
• Wörterbuch effizient über Hashing realisierbar
(insert, remove und find kosten amortisiert /
worst case O(1) Zeit)
1
3
14
5
5
10
3
19
14
1
19
10
• Hashing zerstört Ordnung und erlaubt daher
keine effiziente locate-Operation
27.05.09
Kapitel 7
4
Suchstruktur
Erste Lösung: sortierte Liste (mit Wächter)
null
3
…
19
42
Problem: insert, remove, locate kosten im worst
case Θ (n) Zeit
Einsicht: Wenn locate effizient zu implementieren
wäre, dann auch alle anderen Operationen
27.05.09
Kapitel 7
5
Suchstruktur
Idee: füge Navigationsstruktur hinzu, die
locate effizient macht
Navigationsstruktur
null
27.05.09
3
…
Kapitel 7
19
42
6
Binärer Suchbaum (ideal)
10
3
1
1
27.05.09
19
5
3
5
14
10
Kapitel 7
14
28
19
28
7
Binärer Suchbaum
Suchbaum-Regel:
k
T1
Für alle Schlüssel k´ in T1
und k´´ in T2: k´ < k < k´´
T2
Damit locate Operation einfach zu implementieren.
27.05.09
Kapitel 7
8
locate(k) Operation
k
T1
T2
Für alle Schlüssel k´ in T1
und k´´ in T2: k´< k < k´´
Locate-Strategie:
• Starte in Wurzel des Suchbaums
• Für jeden erreichten Knoten v:
– Falls key(v) > k, gehe zum linken Kind von v, sonst gehe
zum rechten Kind
27.05.09
Kapitel 7
9
Binärer Suchbaum
Formal: für einen Baumknoten v sei
• key(v) der Schlüssel in v
• d(v) die Anzahl Kinder von v
• Suchbaum-Invariante: (s.o.)
• Grad-Invariante:
Alle Baumknoten haben max. zwei Kinder
• Schlüssel-Invariante:
Für jedes Element e in der Liste gibt es genau einen
Baumknoten v mit key(v) == e.key().
27.05.09
Kapitel 7
10
locate(9)
10
3
1
1
27.05.09
19
5
3
5
14
10
Kapitel 7
14
28
19
28
11
Insert und Remove Operationen
Strategie:
• insert(e):
Suche einen Knoten entweder mit e.key() < key und
linkem Nachfolger null oder mit e.key() > key und
rechtem Nachfolger null. Füge für e ein neues
Suchbaumblatt ein, so dass Suchbaum-Regel erfüllt ist.
• removeKey(k):
Suche einen Knoten mit key == k. Lösche den Inhalt des
Knoten. Hat er keine Nachfolger, lösche den ganzen
Knoten. Hat er einen Nachfolger, verkürze. Hat er zwei
Nachfolger, überschreibe ihn mit dem größten Knoten
des linken Nachfolgers.
27.05.09
Kapitel 7
12
Insert(5)
10
14
1
28
1
27.05.09
10
Kapitel 7
14
28
13
Insert(5)
10
14
1
5
1
27.05.09
5
28
10
Kapitel 7
14
28
14
Insert(12)
10
14
1
5
1
27.05.09
5
28
10
Kapitel 7
14
28
15
Insert(12)
10
14
1
5
1
27.05.09
5
12
10
Kapitel 7
12
28
14
28
16
removeKey(1)
10
14
1
5
1
27.05.09
5
12
10
Kapitel 7
12
28
14
28
17
removeKey(1)
10
14
5
5
27.05.09
12
10
Kapitel 7
12
28
14
28
18
removeKey(14)
10
14
5
5
27.05.09
12
10
Kapitel 7
12
28
14
28
19
removeKey(14)
10
14
5
5
27.05.09
12
10
Kapitel 7
12
28
14
28
20
removeKey(14)
10
12
5
5
27.05.09
28
10
Kapitel 7
12
28
21
Datenstruktur
// Item: Typ für
, TreeItem: Typ für
interface Elem<K extends Comparable<K>> { K key();}
class Item<K extends Comparable<K>, E extends Elem<K>> {
// doppelt verketttete Liste von Elementen und Baumknoten
TreeItem<K,E> t = null;
E e = null;
Item<K,E> prev, next;
Item () { prev = next = this;}
Item (E e, TreeItem<K,E> t, Item<K,E> prev, Item<K,E> next) {
this.e = e; this.t = t; this.prev = prev; this.next = next;}
e
Item<K,E> insertBefore(E e, TreeItem<K,E> t) {...}
Item<K,E> insertAfter(E e, TreeItem<K,E> t) {...}
void remove() {...}
}
27.05.09
Kapitel 7
22
Datenstruktur
class TreeItem<K extends Comparable<K>, E extends Elem<K>> {
// Baumknoten mit Schlüssel, Item, Vater und Nachfolgern
K key;
Item<K,E> item = null;
TreeItem<K,E> pa = null;
TreeItem<K,E> lc = null;
TreeItem<K,E> rc = null;
TreeItem(K key,TreeItem<K,E> pa) {
this.key = key; this.pa = pa;
}
...
}
27.05.09
Kapitel 7
k
e
23
Datenstruktur
class SearchTree<K extends Comparable<K>,
E extends Elem<K>> {
// erzeuge leere doppeltverkettete Liste
Item<K,E> l;
TreeItem<K,E>;
SearchTree() {
l = new Item<K,E>();
t = new TreeItem(null,null);
t.item = l;
l.t = t;
}
...
// leerer Baumknoten mit
// Verweis auf leeren Listenknoten
}
27.05.09
Kapitel 7
24
Locate Operation
// in SearchTree
Item<K,E> locate(K key) {
if (t.rc == null) return l;
return t.rc.locate(key); // starte Suche in Wurzel
}
// in TreeItem
Item<K,E> locate(K key) {
switch (key.compareTo (this.key)) {
case -1: if (lc == null) return item;
else return lc.locate(key);
case 0: return item;
case +1: if (rc == null) return item.next;
return rc.locate(key);
}
return null;
}
27.05.09
Kapitel 7
25
Insert Operation
// in SearchTree
void insert(Element e) {
K key = e.key();
if (t.rc == null) {
t.rc = new TreeItem<K,E> (key,t);
t.rc.item = l.insertAfter(e, t.rc);
} else t.rc.insert(e);
}
27.05.09
Kapitel 7
26
Insert Operation
// in TreeItem
void insert (E e) {
K key = e.key();
if (key.compareTo(this.key) < 0) if (lc == null) {
lc = new TreeItem<K,E>(key,this);
lc.item = item.insertBefore(e,lc);
} else lc.insert(e);
else if (rc == null) {
rc = new TreeItem<K,E>(key,this);
rc.item = item.insertAfter(e,rc);
} else rc.insert(e);
}
27.05.09
Kapitel 7
27
RemoveKey Operation
// in SearchTree
void removeKey(K key) {
if (t.rc == null) return;
t.rc. removeKey(key);
}
// in TreeItem
void removeKey(K key) {
switch (key.compareTo(this.key)) {
case -1: if (lc == null) break;
else lc.removeKey(key); break;
case +1: if (rc == null) break;
else rc.removeKey(key); break;
...
27.05.09
Kapitel 7
28
RemoveKey Operation
...
case 0: item.remove();
if (lc == null)
if (this == pa.lc) pa.lc = rc;
else pa.rc = rc;
if (rc!= null) rc.pa = pa;
} else if (rc == null) {
if (this == pa.lc) pa.lc = lc;
else pa.rc = lc;
lc.pa = pa;
} else lc.removeMax(this);
}
// Hochkopieren des Nachfolgers
// Hochkopieren des Nachfolgers
// Korrektur des Vaterverweises
}
27.05.09
Kapitel 7
29
RemoveKey Operation
// in TreeItem
void removeMax(TreeItem<K,E> t) {
if (rc == null) {
item.t = t;
t.item = item; t.key = item.e.key();
if (this == pa.lc) {
pa.lc = lc;
if (lc != null) lc.pa = pa;
} else {
pa.rc = lc;
if (lc != null) lc.pa = pa;
}
} else rc.removeMax(t);
}
27.05.09
Kapitel 7
30
Binärbaum
Problem: Binärbaum kann entarten!
Beispiel: Zahlen werden in sortierter Folge
eingefügt
1
3
locate() benötigt Θ (n)
Zeit im worst case
5
10
14
19
28
1
27.05.09
3
5
10
14
19
Kapitel 7
28
31
(a,b)-Bäume
Problem: Binärbaum kann entarten!
Lösung: (a,b)-Baum
Idee:
• Alle Knoten v außer der Wurzel enthalten
d(v)-1 Schlüssel mit a ≤ d(v) ≤ b, wobei a ≥ 2
und b ≥ 2a-1 ist
• Alle Blätter sind in derselben Ebene
27.05.09
Kapitel 7
32
(a,b)-Bäume
Formal: für einen Baumknoten v sei
• d(v)-1 die Anzahl der Schlüssel in v
• t(v) die Tiefe von v (Wurzel hat Tiefe 0)
• Form-Invariante:
Für alle Blätter v,w: t(v)=t(w)
• Grad-Invariante:
Für alle inneren Knoten v
außer Wurzel: d(v) 2 [a,b],
für Wurzel r: d(r) 2 [2,b]
(sofern #Elemente >1)
27.05.09
Kapitel 7
33
(a,b)-Bäume
Lemma 7.1: Ein (a,b)-Baum für n Elemente
hat Tiefe max. 1+loga (n/2)
Beweis:
• Die Wurzel hat Grad ≥ 2 und jeder andere
innere Knoten hat Grad ≥ a.
• Bei Tiefe t gibt es mindestens 2at-1 Blätter
• n ≥ 2at-1 , t ≤ 1+loga n/2
27.05.09
Kapitel 7
34
(a,b)-Bäume
(a,b)-Suchbaum-Regel:
s1, s2,…,sd-1
T1
T2
....
Für alle Schlüssel k in Ti
und k´ in Ti+1: k < si < k´
Td
Damit locate Operation einfach zu implementieren.
27.05.09
Kapitel 7
35
Locate(9)
10
14 19 28
1 3 5
1
27.05.09
3
5
10
14
Kapitel 7
19
28
36
Insert(e) Operation
Strategie:
• Suche Blatt v, in das e.key() gehört. Finde
benachbartes Element e´ in dem Blatt.
Falls e'.key()>e.key(), füge e vor e´ ein,
ansonsten dahinter.
...
27.05.09
e‘
Kapitel 7
...
37
Insert(e) Operation
Strategie:
• Suche Blatt v, in das e.key() gehört. Finde
benachbartes Element e´ in dem Blatt.
Falls e'.key()>e.key(), füge e vor e´ ein,
ansonsten dahinter.
...
27.05.09
e
Kapitel 7
e‘
...
38
Insert(e) Operation
• Füge e.key() und Verweis auf e in
Baumknoten v ein. Falls v nachher
weniger als b Elemente hat, dann fertig.
v
...
27.05.09
x
v
…x z…
y
z
e
e’
...
...
Kapitel 7
x
…x y z…
y
z
e
e’
...
39
Insert(e) Operation
• Falls v nachher b Elemente enthält, teile v
in zwei Knoten auf.
(Beispiel: a=2,
b=4)
w
… a u' b …
… a b…
v
x
27.05.09
x u u‘ y
e
e’
u
u‘
xu
y
e
y
z
x
Kapitel 7
u
e’
u‘
y
z
40
Insert(e) Operation
• Falls Grad von w größer als b, dann teile
w in zwei Knoten auf (usw, bis Grad ≤ b
oder Wurzel aufgeteilt wurde)
… z …
w
27.05.09
w
x y
x y z t
Kapitel 7
t
41
Insert(8)
a=2, b=4
14
19 28 42
3 5 10
3
27.05.09
5
10
14
Kapitel 7
19
28
42
42
Insert(8)
a=2, b=4
14
19 28 42
3 5 8 10
3
27.05.09
5
8
10
Kapitel 7
14
19
28
42
43
Insert(8)
a=2, b=4
8 14
3
27.05.09
19 28 42
10
3 5
5
8
10
Kapitel 7
14
19
28
42
44
Insert(32)
a=2, b=4
8 14
3
27.05.09
19 28 42
10
3 5
5
8
10
Kapitel 7
14
19
28
42
45
Insert(32)
a=2, b=4
8 14
3
27.05.09
19 28 32 42
10
3 5
5
8
10
Kapitel 7
14
19
28
32
42
46
Insert(32)
a=2, b=4
8 14 32
10
3 5
3
27.05.09
5
8
10
Kapitel 7
3 5
14
19
42
28
32
42
47
Insert Operation
• Form-Invariante:
Für alle Blätter v,w: t(v)=t(w)
Erfüllt durch insert!
• Grad-Invariante:
Für alle inneren Knoten v außer Wurzel: d(v) 2 [a,b],
für Wurzel r: d(r) 2 [2,b]
1) Insert splittet Knoten mit b Schlüsseln in Knoten mit
b/2 bzw. (b-1)/2 Schlüsseln. Wenn b ≥ 2a-1, dann
beide Werte ≥ a-1.
2) Wenn Wurzel b Schlüssel enthält, wird eine neue
Wurzel mit einem Schlüssel d.h. Grad 2 erzeugt.
27.05.09
Kapitel 7
48
removeKey(k) Operation
Strategie:
• Erst locate(k) bis Element e in Liste
erreicht. Falls e.key()==k, entferne e aus
Liste, ansonsten stop.
...
27.05.09
e´
e
Kapitel 7
e´´
...
1
49
RemoveKey(k) Operation
Strategie:
• Erst locate(k) bis Element e in Liste
erreicht. Falls e.key()==k, entferne e aus
Liste, ansonsten stop.
...
27.05.09
e´
e´´
Kapitel 7
...
1
50
RemoveKey(k) Operation
• Entferne Verweis auf e und Schlüssel k vom
Baumknoten v mit e. Falls v ein Blatt ist und
noch a-1 Schlüssel enthält, dann fertig.
v
...
x
v
…x k y…
k
y
...
...
…x y…
x
y
...
e
27.05.09
Kapitel 7
51
RemoveKey(k) Operation
• Falls d(v) < a und direkter Nachbar von v
hat Grad > a Schlüssel, nimm Kante von
diesem Nachbarn. (Beispiel: a=2, b=4)
u k z
u r z
v
k
r s t
x
27.05.09
k
r
s
t
x
Kapitel 7
s
k
r
t
s
t
52
RemoveKey(k) Operation
• Falls d(v) < a und kein direkter Nachbar
von v hat Grad >a, merge v mit Nachbarn.
(Beispiel: a=3, b=5)
u y t
u t
v
x
x
27.05.09
r s
y
r
x y r s
s
t
x
Kapitel 7
y
r
s
t
53
Remove(k) Operation
• Veränderungen hoch bis Wurzel, und
Wurzel hat Grad <2: entferne Wurzel.
x y z
27.05.09
x y z
Kapitel 7
54
Remove(k) Operation
• Falls y in innerem Knoten gelöscht wird,
ersetze durch max. Schlüssel in linkem
Teilbaum. (Beispiel: a=2, b=4)
u z t
x y
x
27.05.09
u y t
x
r s
y
r
s
t
x
Kapitel 7
r s
y
r
s
t
55
Remove(10)
a=2, b=4
10 19
14
1 3 5
1
27.05.09
3
5
10
Kapitel 7
14
28
19
28
56
Remove(10)
a=2, b=4
19
14
1 3 5
1
27.05.09
3
5
14
Kapitel 7
28
19
28
57
Remove(10)
a=2, b=4
5 19
14
1 3
1
27.05.09
3
5
14
Kapitel 7
28
19
28
58
Remove(14)
a=2, b=4
5 19
14
1 3
1
27.05.09
3
5
14
Kapitel 7
28
19
28
59
Remove(14)
a=2, b=4
5 19
28
1 3
1
27.05.09
3
5
19
Kapitel 7
28
60
Remove(14)
a=2, b=4
3 19
1
1
27.05.09
5
3
28
5
19
Kapitel 7
28
61
Remove(3)
a=2, b=4
3 19
1
1
27.05.09
5
3
28
5
19
Kapitel 7
28
62
Remove(3)
a=2, b=4
1 19
5
1
27.05.09
28
5
19
Kapitel 7
28
63
Remove(3)
a=2, b=4
19
1 5
1
27.05.09
28
5
19
Kapitel 7
28
64
Remove(1)
a=2, b=4
19
1 5
1
27.05.09
28
5
19
Kapitel 7
28
65
Remove(1)
a=2, b=4
19
5
28
5
27.05.09
19
Kapitel 7
28
66
Remove Operation
• Form-Invariante:
Für alle Blätter v,w: t(v)=t(w)
Erfüllt durch Remove!
• Grad-Invariante:
Für alle inneren Knoten v außer Wurzel: d(v) 2 [a,b], für
Wurzel r: d(r) 2 [2,b]
1) Remove verschmilzt Knoten mit Grad a-1 mit Knoten
mit Grad a. Wenn b ≥ 2a-1, dann hat resultierender
Knoten Grad ≤ b.
2) Remove verschiebt Kante von Knoten mit Grad >a nach
Knoten mit Grad a-1. Auch OK.
3) Wurzel gelöscht: Kinder vorher verschmolzen, Grad
vom verbleibenden Kind ≥ a (und ≤ b), also auch OK.
27.05.09
Kapitel 7
67
Mehr Operationen
• min/max Operation:
Verwende die first und last Operationen, um das
kleinste oder größte Element auszugeben. Zeit
O(1).
• Bereichsanfragen:
Um alle Elemente im Bereich [x,y] zu suchen,
führe locate(x) aus und durchlaufe dann die
Liste, bis ein Element >y gefunden wird. Zeit
O(log n + Ausgabegröße).
27.05.09
Kapitel 7
68
Mehr Operationen
• Konkatenation:
Ziel: Verknüpfe zwei (a,b)-Bäume T1 und T2
mit s1 und s2 Elementen zu (a,b)-Baum T
(Schlüssel in T1 < Schlüssel in T2)
T1
27.05.09
+
=
T2
Kapitel 7
T
69
Mehr Operationen
• Konkatenation:
Strategie (s1 ≤ s2):
k…
T1
…
27.05.09
k
k
T2
<a Kanten:
wie remove-Op
behandeln
…
Kapitel 7
>b Kanten:
wie insert-Op
behandeln
…
70
Mehr Operationen
• Aufspaltung:
Ziel: Spalte (a,b)-Baum T in (a,b)-Bäume
T1 und T2 bei Schlüssel k auf.
T
…
27.05.09
k
T1
k´
…
…
Kapitel 7
T2
k
k´
71
Split-Operation
1. Suche nach k
Pfad
nach k
v1
: Suchpfad
v2
v3
...
vk
…
27.05.09
k
k´
Kapitel 7
…
72
Split-Operation
2. Aufspaltung entlang Suchpfad
s1 … si si+1 … sd-1
: Suchpfad
s1 … si
si+1 … sd-1
links rechts
k
s1 … k si … sd-1
…
27.05.09
links
s1 …
k
Kapitel 7
rechts
si … sd-1
73
Split-Operation
2. Abbruch bei Aufspaltung:
Fall 1:
Fall 2:
s1>k: Aufspals…
tung hier been- 1
den
….sd-1
k
27.05.09
sd-1<k: Aufspaltung hier beenden
k
Kapitel 7
74
Split-Operation
1. Gradreparatur in den beiden Teilbäumen
Strategie: bottom-up entlang Suchpfad, um
zu gültigen (a,b)-Bäumen zurückzukehren. (Wie bei insert und remove
Operationen.)
27.05.09
Kapitel 7
75
Split(1)
a=2, b=4
10 19
14 17
1 3 5
1
27.05.09
3
5
10
14
Kapitel 7
28
17
19
28
76
Split(1)
10 19
1
1
27.05.09
3
3
14 17
5
5
10
14
Kapitel 7
17
28
19
28
77
Split(5)
a=2, b=4
10 19
14 17
1 3 5
1
27.05.09
3
5
10
14
Kapitel 7
28
17
19
28
78
Split(5)
10 19
14 17
1 3 5
1
27.05.09
3
5
10
14
Kapitel 7
17
28
19
28
79
Split(5)
14 19
10
1 3 5
1
27.05.09
3
5
10
17
14
Kapitel 7
17
28
19
28
80
Split(10)
a=2, b=4
10 19
14 17
1 3 5
1
27.05.09
3
5
10
14
Kapitel 7
17
28
19
28
81
Split(10)
10
19
14 17
1 3 5
1
27.05.09
3
5
10
14
Kapitel 7
17
28
19
28
82
Split(10)
5
19
1 3
1
27.05.09
14 17
10
3
5
10
14
Kapitel 7
17
28
19
28
83
n Update-Operationen
Theorem: Es gibt eine Folge von n insert
und removeKey Operationen im (2,3)Baum, so dass Gesamtanzahl der split
und merge Operationen Ω (n log n) ist.
Beweis: Übung.
27.05.09
Kapitel 7
84
n Update-Operationen
Theorem 7.3: Betrachte einen (a,b)-Baum
mit b ≥ 2a, der anfangs leer ist. Für jede
Folge von n insert und remove Operationen ist die Gesamtanzahl der split und
merge Operationen O(n).
Beweis:
Amortisierte Analyse
(wird nicht in Vorlesung behandelt)
27.05.09
Kapitel 7
85
Zusammenfassung
• Binäre Suchbäume
• (a,b)-Bäume
• Zusätzliche Operationen
• Weiter mit Graphrepräsentationen
(Kapitel 8)
27.05.09
Kapitel 7
86
Externer (a,b)-Baum
Prozessor
Interner Speicher
Größe M
Blockgröße B
Externer Speicher
27.05.09
Kapitel 7
87
Externer (a,b)-Baum
Problem: Minimiere Blocktransfers zwischen internem und
externem Speicher
Lösung:
• verwende b=B (Blockgröße) und a=b/2
• halte oberste loga(M/b) Ebenen des (a,b)-Baums im
internen Speicher (Speicher <= M)
• Lemma 7.1: Tiefe des (a,b)-Baums max.1+bloga (n+1)/2c
• loga[(n+1)/2] - loga(M/b) = loga[(n+1)/(2M)] + logab
• logab = O(1)
• Kosten für insert, remove und locate Operationen:
O(logB(n/M)) Blocktransfers
27.05.09
Kapitel 7
88
Herunterladen