Zusammenfassung - S-Inf

Werbung
Zusammenfassung
Datenstrukturen & Algorithmen
M. Leonard Haufs
Sommersemester 2012
Wichtige Hinweise:
Letzte Bearbeitung: Sonntag, 9. Dezember 2012
Ihr dürft die Zusammenfassung selbstverständlich gerne nutzen.
Ich habe nur eine Bedingung. Wenn ihr Fehler im Dokument findet, schreibt sie mir bitte
an folgende Adresse, damit ich die Zusammenfassung verbessern kann:
[email protected]
Viele der Abbildungen dieser Zusammenfassung sind folgender Vorlesung entnommen:
Datenstrukturen und Algorithmen
Prof. Dr. Joost-Pieter Katoen
(RWTH Aachen, Sommersemester 2012)
Inhaltsverzeichnis
1 Komplexitätsklassen
1
2 Rekursionsgleichungen
1
Rekursionsbäume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
Substitutionsmethode . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
Mastertheorem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
2
3
4
3 Datenstrukturen
1
Listen . . . . . . . . . . . .
2
Bäume . . . . . . . . . . . .
2.1
Binärbäume . . . . .
2.2
Binäre Suchbäume .
2.3
Rot-Schwarz-Bäume
3
Graphen . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5
5
6
6
7
9
11
4 Flüsse
1
Allgemeine Flusseigenschaften . . . . .
1.1
Flussnetzwerke . . . . . . . . .
1.2
Fluss in einem Flussnetzwerk .
1.3
Flüsse zwischen Knotenmengen
2
Ford-Fulkerson-Methode . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
15
15
15
15
16
16
.
.
.
.
.
17
17
17
17
18
19
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5 Algorithmenprinzipien
1
Divide & conquer - Teilen und Beherrschen .
2
Greedy-Algorithmen . . . . . . . . . . . . .
3
Dynamische Programmierung . . . . . . . .
3.1
Rucksackproblem . . . . . . . . . . .
3.2
Longest Common Subsequence (LCS)
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6 Sortieralgorithmen
21
1
Einfache Sortieralgorithmen . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.1
Insertionsort - Sortieren durch einfügen . . . . . . . . . . . . . . . 21
1.2
Selectionsort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
i
Inhaltsverzeichnis
2
3
Höhere Sortieralgorithmen . . . . . . . .
2.1
Heapsort . . . . . . . . . . . . . .
2.2
Countingsort . . . . . . . . . . .
2.3
Mergesort . . . . . . . . . . . . .
2.4
Quicksort . . . . . . . . . . . . .
2.5
Dutch National Flag- Problem . .
Gesamtübersicht über Sortieralgorithmen
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
7 Graphenalgorithmen
1
Graphensuche . . . . . . . . . . . . . . . . . . . . .
1.1
Tiefensuche . . . . . . . . . . . . . . . . . .
1.2
Breitensuche . . . . . . . . . . . . . . . . . .
2
Sharir’s Algorithmus . . . . . . . . . . . . . . . . .
3
Prims Algorithmus . . . . . . . . . . . . . . . . . .
4
Single Source Shortest Path (SSSP) . . . . . . . . .
4.1
Dijkstra-Algorithmus . . . . . . . . . . . . .
4.2
Bellman-Ford-Algorithmus . . . . . . . . . .
5
Topologische Sortierung . . . . . . . . . . . . . . .
6
All Pairs Shortest Paths . . . . . . . . . . . . . . .
6.1
Floyd-Warshall Algorithmus . . . . . . . . .
7
Algorithmen auf Flussnetzwerken . . . . . . . . . .
7.1
Ford-Fulkerson-Methode - Maximaler Fluss .
7.2
Min-cut-max-flow . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
22
22
24
25
26
27
29
.
.
.
.
.
.
.
.
.
.
.
.
.
.
30
30
30
32
33
34
35
35
36
37
39
39
40
40
41
8 Hashing
42
1
Hashfunktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2
Geschlossenes Hashing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3
Offenes Hashing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
9 Algorithmische Geometrie
47
1
Mathematische Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . 47
2
Graham-Scan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
ii
1
Komplexitätsklassen
O(f )
g ∈ O(f ) ⇔ ∃c > 0, n0 : ∀n ≥ n0 : 0 ≤ g(n) ≤ c · f (n)
Alternative Definition:
g ∈ O(f ) ⇔ lim sup
n→∞
g(n)
= c ≥ 0, c 6= ∞
f (n)
Ω(f )
g ∈ Ω(f ) ⇔ ∃c > 0, n0 : ∀n ≥ n0 : c · f (n) ≤ g(n)
Alternative Definition:
g ∈ Ω(f ) ⇔ lim inf
n→∞
g(n)
=c>0
f (n)
Θ(f )
g ∈ Θ(f ) ⇔ ∃c1 , c2 > 0, n0 : ∀n ≥ n0 : c1 · f (n) ≤ g(n) ≤ c2 · f (n)
Alternative Definition:
g(n)
= c, 0 < c < ∞
n→∞ f (n)
g ∈ Θ(f ) ⇔ lim
o(f )
g ∈ o(f ) ⇔ ∀c > 0, n0 : ∀n ≥ n0 : 0 ≤ g(n) ≤ c < f (n)
ω(f )
g ∈ ω(f ) ⇔ ∀c > 0, n0 : ∀n ≥ n0 : f (n) < g(n)
1
a)
n
T (n) = 23T (b 23
c) + 42n.
Die Koeffizienten des Mastertheorems sind: b = 23, c = 23 und somit ist E = log23 23 = 1 und f (n) =
42n 2 ⇥(nE ). Der 2. Fall des Mastertheorem liefert dann:
T (n) 2 ⇥(n· log n)
b)
T (n) = 9T ( n3 ) + 27n
Die Koeffizienten des Mastertheorems sind: b = 9, c = 3 und somit ist E = log3 9 = 2. Da f (n) = 27n 2
2O(n Rekursionsgleichungen
) wenden wir den 1. Fall des Mastertheorem an und erhalten:
2 1
T (n) 2 ⇥(n2 )
c)
T (n) = 2T ( n ) + n log n
2
2
1 Rekursionsbäume
Es gilt b = 2, c = 2. Somit ist E = log2 2 = 1 und f (n) = n log2 n. Hier ist das Mastertheorem nicht
anwendbar da keiner der drei Fälle anwendbar ist:
Allgemeines Prinzip:
• n log2 n 2
/ O(n1 ✏ )
Mithilfe von Rekursionsbäumen
lässt sich die Lösung einer Rekursionsgleichung erraten,
1
•
n
log
n
2
/
⇥(n
)
2
indem die Aufteilung in Teilprobleme iterativ dargestellt wird.
• n log2 n 2
/ ⌦(n1+✏ )
Beispiel:
2T ( n2 ) + n · log
T (0)polynomial
=1
denn n logT2 (n)
n ist=asymptotisch
aber
nicht
größer als n.
2 n,
Wir betrachten den Rekursionsbaum:
T (n)
n · log2 n
n log2 n
T (n/2)
n/2 · log2 n/2
log2 n
T (n/9)
n/18 + 3
T (n/2)
n/2 · log2 n/2
T (n/9)
n/18 + 3
T (n/9)
n/18 + 3
T (0)T (0)T (0)T (0)T (0)T (0)
T (n/9)
n/18 + 3
2 · n/2 log2 n/2
4 · n/4 log2 n/4
T (0)T (0)T (0)T (0)T (0)T (0)
2log2 n = n
aus dem Rekursionsbaum lesen wir eine Komplexität von:
log2 n
log2 n
nlog
2 n
n
log2 n X
X Xn i n n
X
X
log
n+1
ii
2
2 + log
i
T
(n)
=
2
·
·
log
+
2
=
2
·
log
2 · 2nn · (log2 n
2
T (n) =
(2 · i log22i i ) =2n ·(2i
log2 n
log2 2 ) = n(log
n
i
2
2
2
2
i=02
i=0
log2 n
i=0
i=0
i=0
1)
) 2 ⇥(n ·log22 n)
Die Rekursionsgleichung leitet sich wie folgt her:
Wir nutzen die Substitutionsmethode um die Vermutung zu beweisen:
h
X
(Rekursive Kosten auf Ebene i) + Gesamtkosten der Blätter(= c · bh+1 )
i=0
6
mit Verästelungsgrad b.
Bei der Bestimmung der Höhe h ist folgendes zu beachten:
- Ist der Basisfall T(0), so ist die Höhe um 1 erhöht, da zusätzlich die Elemente der
Ebene T(0) betrachtet werden.
2
KAPITEL 2. REKURSIONSGLEICHUNGEN
Typische Höhen:
- T (n) = b · T ( nc )
→ h = logc n
- T (n) = b · T (n − c), c ∈ {1, 2}
→ h=
n
c
√
- T (n) = b · T ( n)
→ h = log2 log2 n
2 Substitutionsmethode
Allgemeines Vorgehen:
- Lösung ’raten’ (z.B. Rekursionsbaum)
- Betrachte die jeweilige Definition des betrachteten Falls (O, Ω,, Θ, o, ω)
- Setze die geratene Lösung in den rekursiven Teil (T (n)) der Rekursionsgleichung
ein und beweise entsprechend der Definition des betrachteten Falls.
- Teile durch Umformen den Term in 2 Teile auf:
- Einem Teil, der einer Konstanten multipliziert mit der beweisenden Schranke
entspricht und
- Einem Restterm, durch Abschätzen über die Konstante die Definition des
Falls bestärkt.
- Gegebenenfalls muss durch Variablentransformation die Rekursionsgleichung zunächst vereinfacht werden.
- Häufigste Transformationen:
- n = 2m ⇔ m = log2 n
- T (2m ) = S(m)
Beispiel:
Bestimme die exakte Lösung der Rekursionsgleichung
√
T (n) = 3 n + 3 mit T (2) = 2.
3
,
T (n) = 16n
3 + 12n
3
) + 4n + 3
2
,T (n)
3
2
= 48n
KAPITEL 2. REKURSIONSGLEICHUNGEN
q.e.d.
zu b)
p
T (n) = T ( 3 n) + 3
m
3
,
T (2m ) = T (2 ) + 3
m
S(m) = S( ) + 3
3
S(m) = 3 · log3 m + S(1)
,
T (n) = 3 · log3 log2 n + 2
,
,
,
S(m) = 3 · log3 m + 2
|Variablentransformation m = log2 n
| Umbenennung T (2m ) = S(m)
| Lösung bekannter Rekursionsgleichung: S(m) = S(
| da S(1) = T (2) = 2 (Anfangsbedingung)
| m = log2 n
2
3 Mastertheorem
n
T (n) = b · T ( ) + f (n)
c
mit b ≤ 1 und c > 1
Anzahl der Blätter im Rekursionsbaum:
nE mit E =
log(b)
log(c)
= logc b
1. f (n) ∈ O(nE− ) (für ein > 0)
→ T (n) ∈ Θ(nE )
2. f (n) ∈ Θ(nE )
→ T (n) ∈ Θ(nE · log(n))
3. f (n) ∈ Ω(nE+ ) (für ein > 0) und
b · f ( nc ) ≤ d · f (n) (für d < 1, n hinreichend groß)
→ T (n) ∈ Θ(f (n))
Grenzen des Mastertheorems:
Das Mastertheoren ist nicht anwendbar, wenn
- die Funktion f (n) negativ ist.
- b oder c ∈
/ N>0 .
- der Unterschied von nE und f (n) nicht polynomiell ist.
4
m
)+3
3
14
I In (Forts.)
Vorlesung 8 (Heapsort) werden wir eine weitere Implementierung
Liste
kennenlernen.
I Element minimum(List l) gibt das Element mit dem kleinsten
Schlüssel zurück.
ú
2
3
4
Beinhaltet das Verschieben aller Elemente „rechts“ von k.
Element maximum(List l) gibt das Element mit dem höchsten
Mittels binärer Suche.
†I
Schlüssel zurück.
Joost-Pieter Katoen
7
Datenstrukturen und Algorithmen
Element successor(List l, Element x) gibt das Nachfolgerelement
von Element x zurück.
Elementare Datenstrukturen
Verkettete Listen
21/39
Element predecessor(List l, Element x) gibt das
Einfach
verkettete
Vorgängerelement
vonListen
Element x zurück.
3
Listen
l.head(
13
14
Datenstrukturen
Datenstrukturen und Algorithmen
25/39
Eine einfach verkettete Liste ist eine rekursive,
dynamische Datenstruktur.
Joost-Pieter Katoen
bestehend aus Schlüssel k sowie Zeiger auf ein
1 Listen Elemente
nachfolgendes Element
I
Elementare Datenstrukturen
Verkettete Listen
Liste.
1 void reverse(List
l) {
Doppelt
verkettete Liste
Eleme
Operation
überg
insert(L,
gibt.
I
last = l.head; next
3 head
pos = last.next;
48
34 sowohl vorwärts
2 als auch rückwärts
25
Eine
doppelt
verkettete
Liste kann
4
last.next
= null;
durchlaufen
werden.
Sie implementiert den ADT Liste.
2
pos
tmp
last
while(posbesitzen
!= null){
Elemente
neben Schlüssel und Nachfolgender
einen weiteren
7
tmp auf
= pos.next;
Zeiger
das
vorherige Element.
verkettete
Listen
I
6
Doppelt
chfolgerelement
pos.next = last;
8
last = pos;
Zusätzlicher
Zeiger tail zeigt auf das letzte Element der Liste
I
9
10
pos = tmp;
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
11
}
13
l.head = last;
14
}
48
next
prev
34
2
23/39
25
head
25/39
Datenstrukturen und Algorithmen
Joost-Pieter Katoen
Laufzeiten
27/39
Verkettete Listen
Laufzeiten
Implementierung
Operation
einen weiteren
der Liste
25
insert(L,x)
remove(L,x)
search(L,k)
minimum(L)
maximum(L)
search(L,k)
minimum(L)
maximum(L)
successor(L,x)
predecessor(L,x)
tail
I
27/39
einfach verkette Liste
doppelt verkettete Liste
⇥(1)
⇥(n)
⇥(n)
⇥(n)
⇥(n)
⇥(n)
⇥(n)
⇥(n)
⇥(1)
⇥(n)
⇥(1)
⇥(1)
⇥(n)
⇥(n)
⇥(n)
⇥(n)
⇥(n)
⇥(n)
⇥(1)
⇥(1)
Suchen eines Schlüssels erfordert einen Durchlauf der gesamten Liste.
Gibt es andere Möglichkeiten, die Daten zu organisieren?
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
5
I
26/39
Datenstrukturen und Algorithmen
Elementare Datenstrukturen
h rückwärts
remove(L,
search(L,
minimum(L
maximum(L
Joost-Pieter
Katoe
search(L,
minimum(L
maximum(L
successor
predecess
tail
Joost-Pieter Katoen
der L
Laufzeite
I void
head zeigt auf das erste Element der Liste
höchsten
void
Elementare Datenstruk
I Listen können
dynamisch
erweitert werden
verkettete
Listen
Einfach Doppelt
verkettete
Listen
I
kleinsten
Eine Liste
Reihenfolg
Joost-Pieter Katoen
I
Verkettete Listen
Listen umdrehen
}
Liste
Einfach verkettete Liste
Elementare Datenstrukturen
while(
tmp =
Joost-Pieter
Katoe
8
pos.n
9
last
10
pos =
Elementare
11
} Datens
6
I
I
void
rev
Binäre
last
Trav=
pos =
last.n
28/39
Suchen
Gibt es
Joost-Pieter Katoen
Vater/Mutter
von B und C
Linkes Kind
von A
2 Bäume
A
Schlüssel
12
KAPITEL 3. t DATENSTRUKTUREN
ri
gh
f
t
le
Rechtes Kind
B
von A
6
C 225
2.1 Binärbäume
29/39
Joost-Pieter Katoen
Allgemeiner
Aufbau
Datenstrukturen und Algorithmen
30/39
Ein Binärbaum
ist ein gerichteter, zykelfreierBinäre
Graph
mit Knoten (nodes, allgemein: verElementare Datenstrukturen
Bäume
tices) V und gerichteten Kanten (edges).
Binärbäume – Begriffe (I)
Wurzel
h (V , E )
ten (edges)
oot).
s 2.
el.
Höhe des Binärbaums = 3
102
innerer
Knoten
6
34
23
Ebene 0
225
103
Ebene 1
1056
40
Ebene 2
Ebene 3
Blatt
31/39
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Begriffsklärung Binärbäume
32/39
- Es gibt genau einen ausgezeichneten Knoten, die Wurzel (root).
- Alle Kanten zeigen von der Wurzel weg.
- Diese Kanten sind Zeiger. Jedes Element bekommt zwei dieser Zeiger (left und
right) zu den nachfolgenden Elementen.
- Der Ausgangsgrad jedes Knotens ist höchstens 2.
- Der Eingangsgrad eines Knoten ist 1, bzw. 0 (bei der Wurzel).
- Sonderfall: Baum mit V = E = ∅.
- Ein Knoten mit leerem linken und rechten Teilbaum heißt Blatt (leaf).
- Die Tiefe (auch: Ebene) eines Knotens ist sein Abstand, d. h. die Pfadlänge, von
der Wurzel.
- Die Höhe eines Baumes ist die maximale Tiefe seiner Blätter.
6
KAPITEL 3. DATENSTRUKTUREN
Allgemeine Eigenschaften
- Ebene d hat höchstens 2d Knoten.
- Mit Höhe h kann ein Binärbaum maximal 2h+1 − 1 Knoten enthalten.
- Mit n Knoten hat ein Binärbaum mindestens die Höhe h = dlog2 n + 1e − 1
Traversierungen
Eine Traversierung ist ein Baumdurchlauf mit folgenden Eigenschaften:
1. Die Traversierung beginnt und endet an der Wurzel.
2. Die Traversierung folgt den Kanten des Baumes. Jede Kante wird genau zweimal
durchlaufen: Einmal von oben nach unten und danach von unten nach oben.
3. Die Teilbäume eines Knotens werden in festgelegter Reihenfolge (zuerst linker,
dann rechter Teilbaum) besucht.
4. Unterschiede bestehen darin, bei welchem Durchlauf man den Knoten selbst (bzw.
das dort gespeicherte Element) „besucht“.
(Die Arraydarstellung einer Traversierung nennt man Linearisierung)
Es gibt 3 verschiedene Formen der Traversierung:
- Inorder-Traversierung: “Scannen von links nach rechts”
Zuerst linken Teilbaum, dann Wurzel, dann rechten Teilbaum ausgeben.
- Preorder-Traversierung: “Wie Einfügereihenfolge”
Zuerst Wurzel, dann linken, dann rechten Teilbaum ausgeben.
- Postorder: “Soweit wie möglich runter”
Zuerst linken, dann rechten Teilbaum, dann Wurzel ausgeben.
2.2 Binäre Suchbäume
Allgemeine Definition
Ein binärer Suchbaum (BST) ist ein Binärbaum, der Elemente mit Schlüsseln enthält,
wobei der Schlüssel jedes Knotens
- mindestens so groß ist, wie jeder Schlüssel im linken Teilbaum und
- höchstens so groß ist, wie jeder Schlüssel im rechten Teilbaum.
Führt man auf einem binären Suchbaum eine Inordertraversierung durch, so erhält man
mit einer Laufzeit von Θ(n) die Schlüssel als Linearisierung in sortierter Reihenfolge.
7
KAPITEL 3. DATENSTRUKTUREN
Operationen auf Binären Suchbäumen
Suchen
Traversiere (durchsuche) den Baum:
- Falls der gesuchte Schlüssel gleich dem aktuell betrachteten Schlüssel ist:
Suche beenden
- Falls der gesuchte Schlüssel kleiner als der aktuell betrachtete Schlüssel ist:
Durchlaufe den linken Teilbaum (linkes Kind ist neuer betrachtete Schlüssel)
- Falls der gesuchte Schlüssel größer als der aktuell betrachtete Schlüssel ist:
Durchlaufe den rechten Teilbaum (rechtes Kind ist neuer betrachtete Schlüssel)
Komplexität: Θ(h)
Einfügen
1. Suche einen geeigneten freien Platz:
Wie bei der regulären Suche, außer dass, selbst bei gefundenem Schlüssel,
weiter abgestiegen wird, bis ein Knoten ohne entsprechendes Kind erreicht
ist.
2. Hänge den neuen Knoten an:
Verbinde den neuen Knoten mit dem gefundenen Vaterknoten.
Komplexität: Θ(h) (wegen der notwendigen Suche)
Nachfolger finden
Es gibt 2 mögliche Fälle:
1. Der rechte Teilbaum existiert:
→ Der Nachfolger ist der linkeste Knoten (das Minimum) im rechten Teilbaum.
2. Der rechte Teilbaum existiert nicht
→ Der Nachfolger ist der jüngste Vorfahre, dessen linker Teilbaum den Ausgangsknoten enthält.
Komplexität: Θ(h)
8
Einfügen von n (unterschiedliche) Schlüssel in zufälliger Reihenfolge in
einem anfangs leeren Baum entsteht.
3. DATENSTRUKTUREN
Annahme: jede der KAPITEL
n! möglichen
Einfügungsordnungen hat die gleiche
Wahrscheinlichkeit.
Löschen
Drei mögliche Fälle:
Theorem (ohne Beweis)
1. Knoten hat keine Kinder: Lösche den Knoten
Die erwartete Höhe eines zufällig erzeugten BSTs mit n Elementen ist
2. Knoten hat ein Kind: Schneide den Knoten aus. Verbinde also den Vater- und den
O(log
n).
Kindknoten direkt miteinander.
Fazit: Im Schnitt verhält sich eine binäre Suchbaum wie ein (fast)
- Finde den Nachfolger.
balancierte
Suchbaum.
3. Knoten hat zwei Kinder:
- Lösche den Nachfolger aus dem Baum.
Joost-Pieter Katoen
- Ersetze
Datenstrukturen und Algorithmen
den Knoten durch dessen Nachfolger.
24/29
Komplexität: Θ(h)
Binäre Suchbäume
Rotationen
Links- und Rechtsrotationen
leftRotate – Konzept und Beispiel
2
leftRotate(1)
1
2
A
rightRotate(2)
C
B
1
A
C
B
Beispiel
Komplexität: Θ(1)
15
2.3 Rot-Schwarz-Bäume
5
Allgemeine Eigenschaften
3
12
20
10 14
17 31
15
leftRotate(5)
12
20
14 haben, hat die
5 eine Farbe
31
17RotEin binärer Suchbaum, dessen Knoten jeweils zusätzlich
Schwarz-Eigenschaft, falls folgende Bedingungen erfüllt sind:
1. Jeder Knoten ist entweder rot oder schwarz.
3
10 13
13 ist schwarz.
2. Die Wurzel
3. Jedes
(externe)
Joost-Pieter
Katoen
Datenstrukturen und Algorithmen
Blatt ist schwarz.
4. Ein roter Knoten hat nur schwarze Kinder.
5. Für jeden Knoten enthalten alle Pfade, die an diesem Knoten starten und in einem
Blatt des Teilbaumes dieses Knotens enden, die gleiche Anzahl schwarzer Knoten.
9
26/29
Einfügen von Schlüssel k in einen RBT – Strategie
Einfügen
KAPITEL
DATENSTRUKTUREN
Zum Einfügen in
einen RBT3.gehen
wir zunächst wie beim BST vor:
I
Finde einen geeigneten, freien Platz.
I Hänge
den eines
neuenKnotens
Knoten an.
Die Schwarzhöhe
bh(x)
x ist die Anzahl schwarzer Knoten bis zu einem
(externen)EsBlatt,
ausgenommen.
Schwarzhöhe bh(t) eines RBT t ist die Schwarzbleibtxdie
Frage nach derDie
Farbe:
Höhe seiner IWurzel.
Färben wir den neuen Knoten schwarz, dann verletzen wir in der
Regel die Schwarz-Höhen-Bedingung.
1
2
3
4
5
6
ElementareIEigenschaften
Färben wir ihn aber rot, dann könnten wir eine Verletzung der
7
Farbbedingungen
bekommen (die
ist schwarz, rote Knoten
Ein Rot-Schwarzbaum
t mit Schwarzhöhe
h =Wurzel
bh(t) hat:
Rot-Schwarz haben
Bäume keine roten Kinder).
Rot-Schwarz-Bäume
– Mindestens
− 1 den
innere
Knoten.
∆ Wir 2h
färben
Knoten
rot – ein Schwarz-Höhen-Verletzung wäre
schwieriger
behandeln.
Einfügen
in zu
einen
RBT – Algorithmus
ie
8
void r
bstI
node
node
node
// s
rbtI
}
– Höchstens I4hRot
− 1istinnere
Knoten.
sozusagen
eine lokale Eigenschaft, schwarz eine globale.
I Behebe daher im letzten Schritt die Farbverletzung.
– Ein Rot-Schwarz-Baum
mit n inneren Knoten hat höchstens die Höhe 2·log(n+1).
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
9/31
Joost-Pieter Kat
Operationen auf Rot-Schwarzbäumen
void Bäume
rbtIns(Tree t, Node node)
{ // Füge node in den Baum t ein
Rot-Schwarz-Bäume
Einfügen1Rot-Schwarz
2
bstIns(t, node); // Einfügen wie beim BST
3 Einfügen
node.left
null;
– =Was
kann passieren? (1)
4
node.right = null;
5
node.color = RED; // eingefügter Knoten immer zunächst rot
c
c
6
// stelle Rot-Schwarz-Eigenschaft
node
node ggf. wieder her
7
rbtInsFix(t, node);
8 }
n
n
Einfüg
c
node
c
node
Der neu eingefügte Knoten ist immer rot.
I Ist die Farbe des Vaterknotens c schwarz (z. B. die Wurzel), haben
- Jeder neu eingefügte Knoten ist rot.
wir kein Problem.
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Ist c aber rot,c schwarz,
dann liegt eine
Rot-Rot-Verletzung
die wir
- Ist derIVaterknoten
ist der
Einfügevorgang vor,
abgeschlossen.
behandeln müssen.
Rot-Schwarz
Bäume
Rot-Schwarz-Bäume
- Ist
derIVaterknoten
c rot,lassen
so muss
Rot-Rot-Verletzung
werden.
Die
unteren Fälle
sichdie
analog
(symmetrisch)
zu behoben
den oberen
Es gibt 3lösen,
mögliche
daherFälle:
betrachten wir nur die beiden oberen Situationen.
Einfügen
– Was kann passieren? (2)
Fall 1: Onkelknoten e ist rot
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Wir müssen nun Großvater d und Onkel e mit berücksichtigen:
d
c
I
c
Wir müs
Der
sich
Fall 1
Ist e rot,
d auf rot
10/31
11/31
d
e
Einfüg
I
I
9/31
Rot-Schwarz Bäu
e
Der Großvater des eingefügten Knotens war schwarz, denn es handelte
sich
vor dem Einfügen um einen korrekten RBT.
- Umfärben von c und e auf schwarz und d auf rot
Fall 1
Ist e rot, dann können wir durch Umfärben von c und e auf schwarz sowie
d auf rot die Rot-Schwarz-Eigenschaft
lokal wieder herstellen.
10
I
Zwei Ebenen weiter oben könnte nun aber eine Rot-Rot-Verletzung
vorliegen, die nach dem selben Schema iterativ aufgelöst werden kann.
I
Ist d allerdings die Wurzel, dann färben wir sie einfach wieder
schwarz. Dadurch erhöht sich die Schwarzhöhe des Baumes um 1.
I
Zwe
vorl
I
Ist d
schw
Joost-Pieter Kat
KAPITEL 3. DATENSTRUKTUREN
- Löse evtl. höher liegende Rot-Rot-Verletzung iterativ auf.
Rot-Schwarz Bäume
Rot-Schwarz-Bäume
- ist d die Wurzel, so wird d wieder schwarz gefärbt.
Einfügene –ist Was
kann
(3)
Fall 2: Onkelknoten
schwarz,
neuerpassieren?
Knoten liegt innen
Ist der Onkel e dagegen schwarz, dann erhalten wir Fall 2 und 3:
d
d
c
e
c
Fall 2
e
Fall 3
- Überführe
um Vater c nach außen.
Fall 2zu Fall 3 durch Rotation
Rot-Schwarz-Bäume
Fall 3: Onkelknoten
e, neuer
liegt außen um c auf Fall 3 reduzieren.
Dieser Fall lässt
sich Knoten
durch Linksrotation
Rot-Schwarz Bäume
Einfügen – Was kann passieren? (4)
I
d 3:
I
c
x
Die Schwarz-Höhe des linken Teilbaumes von d ändert sich dadurch
nicht.bh(·) = x + 1
bh(·) = ???
c
d
Der
bisherige
Vaterknoten xc wird dabei zum
x
x + 1linken, roten Kind, das
≠æ
eine Rot-Rot-Verletzung
mit dem neuen Vater
(c im rechten Bild)
e
d
x
x
x
hat,
die wir mit Fall 3 beheben können.
e
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
13/31
Fall 3
I
Rot-Schwarz Bäume
Rot-Schwarz-Bäume
Zunächst
rotieren wir um d nach rechts, wobei wir
die
- Rotation
in Richtung e um Großvaterknoten d.
Schwarz-Höhen im Auge behalten.
uzieren.
Einfügen – Was kann passieren? (4)
ich dadurch
- d rot
färben.
I Um
die Schwarz-Höhen der Kinder von c wieder in Einklang zu
bringen,färben.
färben wir d rot. Da bh(·)
dessen
linkes Kind ursprünglich am
- c schwarz
=x +1
roten c hing, ist das soweit
unproblematisch.
d
n Kind, das
hten Bild)
x
Komplexität: Θ(log n)
x
13/31
c
e
x
≠æ
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Rot-Schwarz Bäume
Rot-Schwarz-Bäume
3 Graphen
x
bh(·) = x + 1
c
x
d
x
14/31
x
e
Fall 3
Definitionen
Einfügen in
einen RBT – Algorithmus Teil 2
I Zunächst rotieren wir um d nach rechts, wobei wir die
Ein gerichteter Graph G ist ein Paar (V, E) mit
Schwarz-Höhen im Auge behalten.
- einer Menge
Knoten
(vertices)
V und
1 // Behebe I
eventuelle
Rot-Rot-Verletzung
mit Vater
Um
die Schwarz-Höhen
der Kinder
von c wieder in Einklang zu
2 void rbtInsFix(Tree t, Node node) {
bringen,
färben
wir d rot. Da dessen linkes Kind ursprünglich am
3
// solange
noch eine
Rot-Rot-Verletzung
- einer Menge
(geordneter)
Paare
von Knoten E ⊆besteht
V xV , die (gerichtete) Kanten
roten
c
hing,
ist
soweit
4
while (node.parent.color ==das
RED)
{ unproblematisch.
(edges)5 genannt
werden. == node.parent.parent.left) {
if (node.parent
I Färben wir nun c schwarz, dann haben wir wieder einen gültigen
6
// der von uns betrachtete Fall
- Falls E7 eine Menge
ungeordneter
Paare ist,des
heißt
G ungerichtet.
RBT. Die
Schwarzhöhe
Gesamtbaumes
ist unverändert.
leftAdjust(t,
node);
=x +1
x
d
x
e
// möglicherweise wurde node = node.parent.parent gesetzt
8
0
Joost-Pieter
Katoen Graphen G = (V , E ) ist Datenstrukturen
9 (subgraph)
} else
{ eines
Ein Teilgraph
ein GraphundGAlgorithmen
= (V 0 , E 0 ) mit:
// der dazu symmetrischer Fall
rightAdjust(t, node);
10
11
12
ang zu
glich am
13
14
15
}
}
}
t.root.color = BLACK; // Wurzel bleibt schwarz
11
gültigen
ert.
14/31
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
15/31
14/31
KAPITEL 3. DATENSTRUKTUREN
Elementare Graphenalgorithmen I
- V 0 ⊆ V und E 0 ⊆ E.
0
Graphen
Terminologie bei Graphen (III)
0
– Ist V ⊂ V und E ⊂ E, so heißt G’ echter Teilgraph.
A
Elementare Graphenalgorithmen I
C
B
Graphen
- Transponierter Graph: In GT ist die Richtung der Kanten von G umgedreht.
F
D
Terminologie bei Graphen (III)
E
Teilgraph
A
D
A
B
C
D
E
F
B
A
B
D
E
Teilgraph
Vollständiger (und symmetrischer) Digraph
auf vier Knoten
Terminologie bei Graphen
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Grapheigenschaften
E
Vollständiger (und symmetrischer) Digraph
- Der Graph
heißt symmetrisch, wenn aus (v, w) ∈ E folgt (w, v) ∈ E.
auf vier G
Knoten
Joost-Pieter Katoen
- Der Graph G ist vollständig, wenn jedes Paar von Knoten mit einer Kante verbunDatenstrukturen und Algorithmen
9/36
den ist.
- Knoten w ist adjazent zu Knoten v, wenn (v, w) ∈ E.
- Transponiert man G, so erhält man GT = (V, E 0 ) mit (v, w) ∈ E 0 gdw. (w, v) ∈ E.
- Ein Weg von Knoten v nach w ist eine Folge von Kanten (vi , vi+1 ) : v0 v1 v2 ...vk−1 vk ,
so dass v0 = v und vk = w
- Ein Weg, bei dem alle Kanten verschieden sind, heißt Pfad.
- Länge eines Pfades (Weges) ist die Anzahl der durchlaufenen Kanten.
- Knoten w heißt erreichbar von v, wenn es einen Pfad von v nach w gibt.
- Ein Zyklus ist ein nicht-leerer Weg bei dem der Startknoten auch Endknoten ist.
- Ein Zyklus der Form vv heißt Schleife (loop, self-cycle).
- Ein Graph ist azyklisch, wenn er keine Zyklen hat.
12
9/36
Elementare Graphenalgorithmen I
Graphen
3. DATENSTRUKTUREN
Pfade undKAPITEL
Zyklen (II)
A
B
D
E
C
F
Schleife
Zyklus
Beispiele für Wege: AA B
B und
F F,hierBeispiele
fürWege.
Pfade: E D B und C F
B EED D
B und
C F FCwären
Beispiele für
E D B und C F sind Pfade.
Für ungerichtete
Graphen G gilt:
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
11/36
- Ein Graph G heißt zusammenhängend, wenn jeder Knoten von jedem anderen
Knoten aus erreichbar ist.
- Eine Zusammenhangskomponente von G ist ein maximaler zusammenhängender Teilgraph von G.
- In einer Ansammlung von Graphen heißt ein Graph maximal, wenn er von
keinem anderen dieser Graphen ein echter Teilgraph ist.
Für gerichtete Graphen G gilt:
- G heißt stark zusammenhängend, wenn jeder Knoten von jedem anderen aus erreichbar ist.
- G heißt schwach zusammenhängend, wenn der zugehörige ungerichtete Graph (wenn
alle Kanten ungerichtet gemacht worden sind) zusammenhängend ist.
- Eine starke Zusammenhangskomponente von G ist ein maximaler stark zusammenhängender
Teilgraph von G.
Elementare Graphenalgorithmen I
Graphen
Ein nicht
verbundener
Graph kann eindeutig in verschiedene ZusammenhangskompoStarke
Zusammenhangskomponenten
nenten aufgeteilt werden.
Zusammenhangskomponenten
Zusammenhangskomponenten
Ein nicht-zusammenhängender Digraph, aufgeteilt in seine maximalen
zusammenhängenden Teilgraphen.
13
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
16/36
KAPITEL 3. DATENSTRUKTUREN
Darstellung als Adjazenzmatrix und Adjazenzliste
Die Adjazenzmatrix-Darstellung eines Graphen ist durch eine nxn Matrix A gegeben,
wobei A(i, j) = 1, wenn (vi , vj ) ∈ E, sonst 0.
- Wenn G ungerichtet ist, ergibt sich eine symmetrische Adjazenzmatrix A (d.h.
A = AT ). Dann muss nur die Hälfte der Datenmenge gespeichert werden.
→ Platzbedarf: Θ(n2 )
Bei der Darstellung als Array von Adjazenzlisten gibt es ein durch die Nummer des
Knoten indiziertes Array, das jeweils verkettete Listen (Adjazenzlisten) enthält.
- Der i-te Arrayeintrag enthält alle Kanten von G, die von vi „ausgehen“.
- Ist G ungerichtet, dann werden Kanten doppelt gespeichert.
- Kanten, die in G nicht vorkommen, benötigen keinen Speicherplatz.
→
Platzbedarf:
Θ(n
+ m)
Elementare
Graphenalgorithmen
I
Graphen
Darstellung eines gerichteten Graphen
A
D
A
B
C
D
E
F
C
B
F
E
B
E
F
B
D
F
D
E
Adjazenzliste
S
W
W
W
W
W
W
U
Joost-Pieter Katoen
0
0
0
0
0
0
1
0
0
1
0
0
0
0
0
0
0
0
1
0
0
0
1
0
0
1
1
0
0
0
0
0
1
0
0
1
Adjazenzmatrix
T
X
X
X
X
X
X
V
Datenstrukturen und Algorithmen
20/36
Abbildung 3.1: Beispiel für die Darstellung als Adjazenzmatrix und Adjazenzliste
14
4
Flüsse
1 Allgemeine Flusseigenschaften
1.1 Flussnetzwerke
Ein Flussnetzwerk ist ein gerichteter Graph, dessen Kanten die Zusatzinformation der
Kapazität tragen (Kanten sind wie Wasserrohre).s, t ∈ V (Quelle s, Senke t) sind ausgezeichnete Knoten des Netzwerkes.
– An der Quelle wird produziert
– An der Senke wird verbraucht
– Kapazität = maximale Durchsatzrate
1.2 Fluss in einem Flussnetzwerk
Ein Fluss f hat folgende Eigenschaften:
Beschränkung: Für v ∈ V gilt: f (u, v) ≤ c(u, v).
Ein Fluss f ist also immer maximal so groß wie die Kapazität c.
Asymmetrie: Für v ∈ V gilt: f (u, v) = −f (v, u)
Wird die Flussrichtung umgekehrt, so ändert sich das Vorzeichen des Flusses.
Flusserhaltung: Für u ∈ V − {s, t} gilt: Σv∈V f (u, v) = 0
Was in einen inneren Knoten, der weder Quelle noch Senke ist, hineinfließt
kommt auch wieder heraus.
– f(u,v) ist der Fluss vom Knoten u zum Knoten v.
– Der Wert |f| eines Flusses f ist der Gesamtfluss aus der Quelle s:
X
|f | =
f (s, V )
v∈V
– Ein maximaler Fluss ist einen Fluss mit maximalem Wert für ein Flussnetzwerk.
15
Maximaler Fluss
Flussnetzwerke
Flüsse zwischen Knotenmengen
KAPITEL 4. FLÜSSE
Notationen
Maximaler Fluss
Flussnetzwerke
ÿ
f (x , Y Knotenmengen
) =
f (x , y )
für Y
1.3 Flüsse
zwischen
Flüsse
zwischen
Knotenmengen
y œY
ÿ
Notationen f (X , y ) =
f (x , y )
ÿ
x œX
f (x , Y ) = ÿ ÿ
f (x , y )
f (X , Y ) =
f (X , y ) =
y œY
ÿ
x œX y œY
x œX
für X ™ V
für Y ™ V
f (x , y )
für X , Y ™ V
f (x , y )
ÿ ÿ Mengen
Eigenschaften von Flüssen zwischen
f (X , Y ) =
nken geben.
e“ in ein
en geben.
in ein
2)
1)
4
21/42
f (x , y )
für X ™ V
für X , Y ™ V
Falls f ein Fluss für Flussnetzwerk
x œX yG
œY= (V , E , c) ist, dann gilt:
1.
f (X , X ) = 0
für X ™ V
Eigenschaften
Flüssen
2.
f (X , Yvon
) = ≠f
(Y , X )zwischen Mengen
für X , Y ™ V
3. ff (X
Y , Z )für
= Flussnetzwerk
f (X , Z ) + f (Y ,GZ )= (V
für, EX,,c)
Y ,ist,
Z ™dann
V : Xgilt:
flY =?
Falls
einfiFluss
4. f (Z , fX(X
fi ,YX))==f 0(Z , X ) + f (Z , Y ) fürfür
X ,X
Y ,™Z V™ V : X fl Y = ?
1.
2.
f (X , Y ) = ≠f (Y , X )
Joost-Pieter Katoen
3. f (X fi Y , Z ) = f (X , Z ) + f (Y , Z )
Maximaler Fluss
für X , Y ™ V
Datenstrukturen und Algorithmen
2 Ford-Fulkerson-Methode
4. f (Z , X fi Y ) = f (Z , X ) + f (Z , Y )
21/42
™V
22/42
für X , Y , Z ™ V : X fl Y = ?
für X , Y , Z ™ V : X fl Y = ?
Flussnetzwerke
Eingehender Fluss in der Senke
Datenstrukturen und Algorithmen
Prinzip Joost-Pieter Katoen
22/42
Wie groß ist der an der Senke eingehende Fluss?
– Überführe
Maximaler Flussden Graphen in ein Flussnetzwerk.
Flussnetzwerke
Aufgrund der Flusserhaltung in alle Zwischenknoten ist zu erwarten, dass
er dem
austretenden
Fluss
der Quelles entspricht:
– Suche
einen
beliebigen
Pfadan
und t heraus.
Eingehender
Fluss
inzwischen
der Senke
4
groß ist der
der Senke
Fluss?
f Kapazität
(s,eingehende
V ) = f (V(maximalen
, t)
–Wie
Bestimme
die an
minimale
Durchfluss) dieses Pfades.
4
–Aufgrund
Bestimme
Flusserhöhung,
der Flussist
entlang
des Pfades
Beweis:
der die
Flusserhaltung
in alleindem
Zwischenknoten
zu erwarten,
dass gleich der
Kapazität
der
Kante
mit
der
minimalen
Kapazität
gesetzt
wird.
er dem austretenden Fluss an der Quelle entspricht:
f (s, V ) = f (V , V ) ≠ f (V ≠ {s}, V )
| Eigenschaft 3
– Bilde das Restnetzwerk, indem der Durchfluss als umgekehrte Kanten einge= ≠f (V ≠ {s}, V
| Eigenschaft 1
(s,) V ) = f (V , t)
zeichnet wird (eventuell fexistierende
Gegenpfade werden verrechnet).
4
Beweis:
= f (V , V ≠ {s})
| Eigenschaft 2
– Fahre solange fort,
suchen,
augmentierende
(den Fluss
= f neue
(V , t)Pfade
+ f (V ,zu
V≠
{s, t}) bis es keine
| Eigenschaft
4
weiter vergrößernde)
Pfade
mehr
gibt,
d.h.
die
Senke
noch
von
der
Quelle
aus
| Flusserhaltung
f (s, V ) =
=ff(V
(V, ,t).
V ) ≠ f (V ≠ {s}, V )
| Eigenschaft 3
erreichbar ist.
= ≠f (V ≠ {s}, V )
mmetrie.
23/42
| Eigenschaft 1
= f (V
{s}) aller Flusserhöhungen.
| Eigenschaft 2
→ Der Maximale Fluss
ist, V
die≠Summe
Joost-Pieter Katoen
= f (V , t) + f (V , V ≠Datenstrukturen
{s, t}) und Algorithmen
| Eigenschaft 4
= f (V , t).
24/42
| Flusserhaltung
metrie.
23/42
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
16
24/42
5
Algorithmenprinzipien
1 Divide & conquer - Teilen und Beherrschen
Das Prinzip hinter Divide & conquer- Algorithmen ist, dass sie ein Problem in kleinere
Teilprobleme teilen, die zwar dem ursprünglichen Problem ähneln, jedoch eine kleinere
Größe besitzen. Die Teilprobleme werden dabei rekursiv gelöst. Anschließend werden die
Lösungen der Teilprobleme dann kombiniert, um daraus die Lösung des Ursprungsproblems zu erhalten. Das Paradigma umfasst drei Schritte:
- Teile das Problem in eine Anzahl von Teilproblemen auf.
- Beherrsche die Teilprobleme durch rekursives Lösen. Hinreichend kleine Teilprobleme werden direkt gelöst.
- Verbinde die Lösungen der Teilprobleme zur Lösung des Ausgangsproblems.
2 Greedy-Algorithmen
Greedy(‘gierige’) Algorithmen sind dadurch gekennzeichnet, dass sie in jedem Schritt
eine kuzfristig optimale Lösung wählen. Diese Lösungsfindung sollte eine möglichst geringe Komplexität haben. Nachdem eine Wahl für eine Lösung getroffen wurde ist diese
nicht mehr rückgängig zu machen.
Die Lösungsstrategie eines Greedy-Algorithmus’ ist optimal, wenn sie sich aus optimalen
Teilproblemen zusammensetzt, die unabhängig von anderen Teillösungen sind.
3 Dynamische Programmierung
Dynamische Programmierungs-Probleme sind Optimierungsprobleme, also Probleme, für
die es verschiedene Lösungsmöglichkeiten mit einer Minimierung von Kosten oder einer
Maximierung eines Wertes gibt. Damit Dynamische Programmierung möglich ist, muss
die optimale Lösung aus sich überlappenden Teilproblemen bestehen, die sich rekursiv
aufeinander beziehen.
17
KAPITEL 5. ALGORITHMENPRINZIPIEN
Allgemeines Vorgehen
1. Stelle die Rekursionsgleichung (top-down) für den Wert der Lösung auf.
– Dabei sind folgende Punkte zu klären:
– Festlegung der Basisfälle
– Unterscheidung zwischen Maximierungs- und Minimierungsproblem.
– Festlegung der Abbruchbedingungen
2. Löse die Rekursionsgleichung bottom-up.
3. Bestimme aus dem Wert der Lösung die Argumente der Lösung.
4. Rekonstruiere die Lösung.
– dies geschieht durch aufstellen einer Lösungstabelle, die entsprechend der Rekursionsgleichung ausgefüllt wird.
3.1 Rucksackproblem
Gegeben sei ein Rucksack, mit maximaler Tragkraft M, sowie n Gegenstände, die sowohl ein Gewicht als auch einen Wert haben. Nehme möglichst viel Wert mit, ohne den
Dynamische Programmierung
Anwendungen
Rucksack zu überladen.
Das Rucksackproblem – Rekursionsgleichung (II)
Rekursionsgleichung
Sei also C [i, j] der maximale Wert des Rucksacks mit Tragkraft j, wenn
Sei also C[i, j] der
Wert des
mit Tragkraft j, wenn nur die Gegenmanmaximale
nur die Gegenstände
{ 0, .Rucksacks
. . , i ≠ 1 } berücksichtigt.
stände 0, ..., i − 1 berücksichtigt werden.
Es ergibt sich folgende Rekursionsgleichung:
C [i, j] =
I
Y
_
] max(C [i≠1, j], ci≠1 + C [i≠1, j≠wi≠1 ])
≠Œ
_
[ 0
für j < 0
für i = 0, j > 0
Dann ist cmax = C [n, M].
Diese Rekursionsgleichung lösen wir nun bottom-up, indem wir die
Rucksäckewmit
möglichenc Gewichten
// Eingabe : Gewichte
[ i ]allen
, Werte
[ i ] , T {r 0,
a g. .k. r, M
a f}t berechnen,
M
wenn
wir
jeweils
einen
weiteren
Gegenstand
hinzunehmen.
int knapDP ( int w[ n ] , int c [ n ] , int n , int M) {
I
1
3
5
7
9
11
int C[ n+1,M+ 1 ] ;
// Array i n i t i a l i s i e r e n
fo r ( int Joost-Pieter
j = 0Katoen
; j <= M; j ++)
Datenstrukturen und Algorithmen
22/31
C[ 0 , j ] = 0 ;
// B a s i s f a l l
fo r ( int i = 1 ; i <= n ; i ++){
fo r ( int j = 0 ; j <= M; j ++)
i f (w [ i −1] <= j ) {
C[ i , j ] = max(C[ i −1, j ] , c [ i −1] + C[ i −1, j −w[ i − 1 ] ] ) ;
} else
C[ i , j ] = C[ i −1, j ] ; // p a s s t n i c h t
}
18
Das Rucksackproblem – Rekonstruktion
Offen ist noch
die Frage,
Gegenstände (S ™ G) nun eigentlich
KAPITEL
5. welche
ALGORITHMENPRINZIPIEN
mitgenommen werden müssen, um cmax zu erreichen.
return C[ n ,M] ;
13
}
Beispiel
Beispiel
w[] = { 2, 12, 1, 1, 4 }, c[] = { 2, 4, 2, 1, 10 }, M = 15
0
1
0
0
0
0
0
0
0
1
2
3
4
5
0
0
0
2
2
2
2
0
2
2
2
3
3
3
4
5
6
7
8
9
10
11
12
13
14
15
0 0 0 0 0 0 0 0 0 0 0 0 0
2 2 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 4 4 6 6
4 4 4 4 4 4 4 4 4 4 6 6 8
4 5 5 5 5 5 5 5 5 5 6 7 8
4 10 12 13 14 15 15 15 15 15 15 15 15
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
25/31
3.2 Longest Common Subsequence (LCS)
Sei A = (a1 , ..., am ) eine Sequenz. Die Sequenz Aik = (ai1 , ..., aik ) ist eine Teilsequenz
von A wobei i1 < i2 < ... < ik und ij ∈ 1, ..., m.
Dynamische Programmierung
Anwendungen
Beispiel: bca ist eine gemeinsame Teilsequenz von A = abcbdab und B = bdcaba.
Longest Common Subsequence –
Rekursionsgleichung
Rekursiongleichung
Hier lässt sich die Rekursiongleichung für den Wert, also die Länge der LCS aufstellen:
Wir können
wieder die Rekursiongleichung für den Wert, also die Länge
L[i, j] = |LCS(A
i , Bj )|
der LCS aufstellen: L[i, j] = |LCS(Ai , Bj )|
L[i, j] =
2
4
6
8
10
12
Y
0
_
_
]
_
_
[
für i = 0 oder j = 0
L[i ≠ 1, j ≠ 1] + 1
falls ai = bj , i, j > 0
max(L[i, j ≠ 1], L[i ≠ 1, j]) falls ai ”= bj , i, j > 0
I
Das lässt sich direkt als Algorithmus umsetzen (Hausaufgabe).
I
Dessen Laufzeit ist O(|A|·|B|), ebenso seine Platzkomplexität.
int l c s ( int Is e q 1 [ ] , int l 1 , int s e q 2 [ ] , int l 2 ) {
Ähnlich dem Rucksackproblem lässt sich dann die LCS rekonstruieren.
int L [ l 1 +1, l 2 + 1 ] ;
fo r ( int i = 0 ; i i= l 1 ; i ++)
L[ i , 0 ] = 0;
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
30/31
fo r ( int
j = 0 ; j i= l 2 ; j ++)
L[0 , j ] = 0;
fo r ( int i = 1 ; i i= l 1 ; i ++) {
fo r ( int j = 1 ; j i= l 2 ; j ++) {
i f ( s e q 1 [ i ] == s e q 2 [ j ] ) {
L[ i , j ] = L[ i − 1 , j − 1] + 1;
} e l s e i f (L [ i − 1 , j ] > L [ i , j − 1 ] ) {
19
KAPITEL 5. ALGORITHMENPRINZIPIEN
L[ i , j ] = L[ i − 1 , j ] ;
} else {
L[ i , j ] = L[ i , j − 1];
}
14
16
}
return L [ l 1 , l 2 ] ;
18
}
20
6
Sortieralgorithmen
1 Sortieren
Einfache Sortieralgorithmen
Sortieren durch Einfügen
1.1 Sortieren
Insertionsort
- Sortieren
durch
einfügen
durch
Einfügen
– Insertionsort
Prinzip:
0 12 17 17 19 8 25 3 6 69 26 4 2 13 34 41
bereits sortiert
noch unsortiert
als Nächstes einzusortieren
- Beginne beim zweiten Element.
I
Durchlaufen des (unsortierten) Arrays von links nach rechts.
- Der unsortierte Bereich des Arrays wird von links nach rechts durchlaufen.
- Gehe zun ersten bisher noch nicht berücksichtigten Element.
- Suche die richtige Position für das Element im bereits sortierten Arrayabschnitt.
- Füge das Element an die richtige Stelle ein.
- Verschiebe alle bereits sortierten Elemente Rechts vom eingefügten Element um 1
nach rechts.
⇒Joost-Pieter
Wiederhole
erreicht
ist.
Katoen solange, bis das Ende des Arays
Datenstrukturen
und Algorithmen
1
3
5
7
9
11
void i n s e r t i o n S o r t ( n ) {
fo r ( i = 1 ; i < n ; i ++){
i f (E [ i ] < E [ i −1]){
int temp = E [ i ] ;
f o r ( j = i ; j >0 && E [ j −1] > temp ; j −−){
E[ j ] = E[ j −1];
}
E [ j ] = temp ;
}
}
}
21
17/32
KAPITEL 6. SORTIERALGORITHMEN
1.2 Selectionsort
Prinzip:
1. Setze Pointer i auf das erste Element.
2. Suche kleinstes Element rechts von i und speichere die Position dieses Elementes
als m.
3. Vertausche i. Element mit dem Wert des Elementes an Position m.
Setze i um eins hoch.
⇒ Wiederhole 2./3. bis Ende des Arrays erreicht.
1
3
5
7
9
11
13
void s e l e c t i o n S o r t ( Array E) {
int i , j ,m;
fo r ( i = 0 ; i < E . l e n g t h ; i ++) {
m= i;
fo r ( j = i + 1 ; j < E . l e n g t h ; j ++) {
i f (E [ j ] <= E [m] ) {
m= j;
}
}
int v = E [ i ] ;
E [ i ] = E [m] ;
E [m] = v ;
}
}
2 Höhere Sortieralgorithmen
2.1 Heapsort
Prinzip:
1. Heapsort:
- buildHeap: Heap aus Array aufbauen.
- Beginne beim letzten Element und gehe nach vorne durch, bis der Arrayanfang
erreicht ist:
- Tausche das erste Arrayelement mit dem aktuell betrachteten.
- Heapify: Stelle die Heapeigenschaft wieder her.
2. Heapify (Heapeigenschaft wiederherstellen):
- Beginne beim letzten Element und gehe rückwärts bis zum ersten Element:
22
KAPITEL 6. SORTIERALGORITHMEN
- Finde das Maximum der Werte A[i] und seiner Kinder
- Is A[i] bereits das größte Element, dann ist der gesamte Teilbaum auch
ein Heap.
- Sonst: Tausche A[i] mit dem größten Element und führe Heapify erneut in diesem Unterbaum aus.
2
4
void buildHeap ( int E [ ] ) {
fo r ( int i = E . l e n g t h / 2 − 1 ; i >= 0 ; i −−) {
h e a p i f y (E , E . l e n g t h , i ) ;
}
}
6
8
10
12
14
16
18
20
22
24
26
28
void h ea p S o r t ( int [ ] E) {
buildHeap (E ) ;
fo r ( int i = E . l e n g t h − 1 ; i > 0 ; i −−) {
swap (E [ 0 ] , E [ i ] ) ;
h e a p i f y (E , i , 0 ) ;
}
}
void h e a p i f y ( int [ ] E , int n , int pos ) {
int next = 2 ∗ pos + 1 ;
while ( next < n ) {
( next + 1 < n && E [ next + 1 ] > E [ next ] ) {
next = next + 1 ;
}
i f (E [ pos ] > E [ next ] ) {
break ;
}
swap (E [ pos ] , E [ next ] ) ;
pos = next ;
next = 2 ∗ pos + 1 ;
}
}
23
KAPITEL 6. SORTIERALGORITHMEN
Beispiel für Heapsort mit Eingabearray E = [12, 6, 8, 3, 4, 0, 2]
2.2 Countingsort
Prinzip:
- Zunächst ein Histogramm- Hilfsarray erstellen, in dem die Häufigkeit jeder Zahl
gespeichert wird.
- Positionsarray erstellen, in dem von links nach rechts die Werte des HistogrammArrays aufaddiert werden.
Beispiel:
Histogramm:
Positionen:
2
2
0
2+0
0
2+0
1
2+1
2
3+2
1
5+1
- Ausgabearray von hinten nach vorne erstellen, indem die neue Position der Zahl
X im Eingabearray der Wert an Position (X − 1) des Positionsarrays ist.
- Der Wert des Positionsarrays wird anschließend um 1 verringert.
24
KAPITEL 6. SORTIERALGORITHMEN
Beispiel:
Eingabe:
6
8
0
0 1
Histogramm: 2 0
Positionen
2 2
Ausgabearray
0 1 2 3 4 5
4
0
4
0
4 4
0
4 4 5
0 3 4 4 5
0 0 3 4 4 5
0 0 3 4 4 5
0 0 3 4 4 5
1
3
5
7
9
11
13
15
17
3
5
4
2
0
2
3
1
3
6
7
6
8
8
0
4
2
5
0
2
1
1
1
1
0
0
0
4
5
1
6
1
2
2
2
2
2
2
2
2
6
1
7
7 8
0 1
7 8
Positionsarray
2 3 4 5 6
2 3 4 6 7
2 3 4 6 7
2 3 3 6 7
2 3 3 5 7
2 2 3 5 7
2 2 3 5 7
2 2 3 5 7
2 2 3 5 7
7
7
7
7
7
7
7
7
6
8
8
8
8
8
8
8
7
7
int [ n ] c o u n t i n g S o r t ( int [ ] E , int n , int k ) {
int [ ] h i s t o g r a m = new int [ k ] ; // D i r e k t e A d r e s s i e r u n g s t a b e l l e
fo r ( int i = 0 ; i < 0 ; i ++){
histogramm [ E [ i ] ] + + ;
// Zä h l e Hä u f i g k e i t
}
fo r ( int i = 1 ; i < k ; i ++){
// Berechne P o s i t i o n
histogramm [ i ] = h i s t o g r a m [ i ] + h i s t o g r a m [ i − 1 ] ;
}
// Berechne P o s i t i o n
int e r g e b n i s [ n ] ;
fo r ( int i = n − 1 ; i >= 0 ; i −−){
// l ä u f t nur s t a b i l , wenn r ückwä r t s g e z ä h l t wird .
h i s t o g r a m [ E [ i ]] − −;
r e s u l t [ histogram [E[ i ] ] ] = E[ i ] ;
}
return r e s u l t ;
}
2.3 Mergesort
Prinzip:
- Teile das Zahlenarray in zwei (möglichst) gleichgroße Hälften auf.
- Beherrsche: Sortiere die Teile durch rekursives Mergesort-aufrufen.
- Verbinde je zwei bereits sortierte Teilsequenzen zu einen einzigen sortierten Array.
25
KAPITEL 6. SORTIERALGORITHMEN
1
3
5
7
9
// A u f r u f : mergeSort (E , 0 , E . l e n g t h −1);
void mergeSort ( Array E , int l i n k s , int r e c h t s ) {
if ( l e f t < right ) {
int mid = ( l e f t + r i g h t ) / 2 ;
// f i n d e Mitte
mergeSort (E , l e f t , mid ) ;
// s o r t i e r e l i n k e H a e l f t e
mergeSort (E , mid + 1 , r i g h t ) ;
// s o r t i e r e r e c h t e H a e l f t e
// Verschmelzen d e r s o r t i e r t e n H a e l f t e n
merge (E , l e f t , mid , r i g h t ) ;
}
}
11
13
15
17
19
21
23
25
27
void merge ( int E [ ] , int l e f t , int mid , int r i g h t ) {
int a = l e f t ,
b = mid + 1 ;
int Eold [ ] = E ;
fo r ( int l e f t = 0 ; l e f t <= r i g h t ; l e f t ++) {
i f ( a > mid ) { // Wir w i s s e n ( Widerspruch ) : b <= r i g h t
E [ l e f t ] = Eold [ b ] ;
b++;
} e l s e i f ( b > r i g h t | | Eold [ a ] <= Eold [ b ] ) {
E [ l e f t ] = Eold [ a ] ;
a++
} else {
E [ l e f t ] = Eold [ b ] ;
b++;
}
}
}
2.4 Quicksort
Prinzip
Die Elemente werden zunächst auf die richtige Hälfte des Arrays gebracht, und dann
rekursiv sortiert.
1. Teile: Ein Pivotelement aus dem Array auswählen, Array in zwei Hälften aufteilen:
- Kleiner als das Pivotelement
- Mindestens so groß wie das Pivotelement
2. Beherrsche: Die Teile rekursiv sortieren, das Pivotelement zwischen die sortierten
Teile setzen.
Prinzip der Partitionierung:
- Es werden drei Bereiche eingesetzt: “< Pivot”, “> Pivot” und “ungeprüft”.
26
Quicksort
Quicksort
KAPITEL 6. SORTIERALGORITHMEN
Quicksort – Strategie
41 26 17 25 19 17 8 3 6 69 12 4 2 13 34 0
Pivot
Partitionierung
8 3 6 12 4 2 13 0 17 41 26 17 69 25 19 34
< Pivot
> Pivot
- Solange das zusätzliche Element “< Pivot” ist, schicke die linke Grenze nach rechts.
- Solange das zusätzliche Element “>= Pivot” ist, schiebe die rechte Grenze nach
links.
- Tausche das links gefundene mit dem rechts gefundenen.
⇒ Fahre fort, bis sich die Grenzen treffen.
Joost-Pieter Katoen
1
3
5
7
Datenstrukturen und Algorithmen
6/20
void q u i c k S o r t ( int E [ ] , int l e f t , int r i g h t ) {
if ( l e f t < right ) {
int i = p a r t i t i o n (E , l e f t , r i g h t ) ;
// i i s t P o s i t i o n d e s P i v o t e l e m e n t e s
q u i c k S o r t (E , l e f t , i − 1 ) ; // s o r t i e r e den l i n k e n T e i l
q u i c k S o r t (E , i + 1 , r i g h t ) ; // s o r t i e r e den r e c h t e n T e i l
}
}
9
11
13
15
17
19
21
23
int p a r t i t i o n ( int E [ ] , int l e f t , int r i g h t ) {
// Wä h l e e i n f a c h e s P i v o t e l e m e n t
int ppos = r i g h t , p i v o t = E [ ppos ] ;
while ( true ) {
// B i l i n e a r e Suche
while ( l e f t < r i g h t && E [ l e f t ] < p i v o t ) l e f t ++;
while ( l e f t < r i g h t && E [ r i g h t ] >= p i v o t ) r i g h t −−;
i f ( l e f t >= r i g h t ) {
break ;
}
swap (E [ l e f t ] , E [ r i g h t ] ) ;
}
swap (E [ l e f t ] , E [ ppos ] ) ;
return l e f t ; // g i b neue P i v o t p o s i t i o n a l s S p l i t p u n k t z u r ück
}
2.5 Dutch National Flag- Problem
Prinzip: Jedes Feld eines Arrays kann drei mögliche Werte haben: Rot, Weiß oder Blau.
27
KAPITEL 6. SORTIERALGORITHMEN
- Teile das Array in vier Regionen auf:
1. 0 < i ≤ r
Sortieren
Sortieren - Einführung
2. u < iFlag
< b Problem (IV)
Dutch National
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
3. b ≤ i ≤ n
void DutchNationalFlag(Color
E[], int n) {
int r = 0, b = n + 1; // rote und blaue Regionen sind leer
gibt
Zeiger:
int -u Es
= 1;
// 3weiße
Region ist leer, die unbekannte == E
while (u < b) {
- r:
if (E[u]
== Rote
rot) {Region
swap(E[r
1], E[u]);
- b:+ Blaue
Region
r = r + 1; // vergrößere die rote Region
u = u -+ u:
1; Unbekannte
// verkleinere
die unbekannte Region
Region
}
if (E[u] == weiss) {
r u
b
u = u + 1;
}
if (E[u] == blau) {
swap(E[b - 1], E[u]);
b = b - 1; //Zeigerstartposition
vergrößere die blaue
Region
beim
Dutch National Flag- Problem
}
}
}
- Steht u auf einem roten Feld, wird E[u] mit E[r + 1] vertauscht
und der rote
Bereich vergrößert und der unbekannte Bereich um 1 verringert (r++, u++)
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
13/32
- Steht u auf einem weißen
Feld, wird der unbekannte
Bereich um 1 verkleinert
(u++)
- Steht u auf einem blauen Feld, wird E[u] mit E[b−1] vertauscht. Der blaue Bereich
erhöht sich um 1. (b–, u bleibt gleich!)
⇒ Der Algorithmus terminiert, wenn u = b.
In jedem Schritt wird entweder u erhöht, oder b verringert.
2
4
6
8
10
12
14
16
18
void Dut c h N a t i o n a l F l a g ( C o l o r E [ ] , int n ) {
int r = 0 , b = n + 1 ; // r o t e und b l a u e Regionen s i n d l e e r
int u = 1 ; // wei ß e Region i s t l e e r , d i e unbekannte == E
while ( u < b ) {
i f (E [ u ] == r o t ) {
swap (E [ r + 1 ] , E [ u ] ) ;
r = r +1; // v e r g r ö ß e r e d i e r o t e Region
u = u + 1 ; // v e r k l e i n e r e d i e unbekannte Region
}
i f (E [ u ] == w e i s s ) {
u = u + 1;
}
i f (E [ u ] == b l a u ) {
swap (E [ b − 1 ] , E [ u ] ) ;
b = b−1; // v e r g r ö ß e r e d i e b l a u e Region
}
}
}
28
KAPITEL 6. SORTIERALGORITHMEN
3 Gesamtübersicht über Sortieralgorithmen
Laufzeitkomplexität
Algorithmus
Worst case Average case Speicher Stabilität
Insertionsort
Θ(n2 )
Θ(n2 )
in-place
stabil
2
Selectionsort
Θ(n )
Θ(n2 )
in-place
nicht stabil (*)
Quicksort
Θ(n2 )
Θ(n log n)
Θ(log n)
nicht stabil(*)
Mergesort
Θ(n log n)
Θ(n log n)
Θ(n)
stabil
Heapsort
Θ(n log n)
Θ(n log n)
in-place
nicht stabil
1
Countingsort
Θ(n + k)
Θ(n + k)
O(n + k) stabil
Dutch National Flag Θ(n)
Θ(n)
in place
nicht stabil
(*): Vorlesungsversion ist nicht stabil, es existiert jedoch auch eine stabile Version.
29
7
Graphenalgorithmen
1 Graphensuche
1.1 Tiefensuche
(Tiefensuche: Depth-First Search, DFS)
Prinzip:
– Alle Knoten als ’nicht gefunden’ markieren.
– Aktuellen Knoten als ’gefunden’ markieren.
– Jede Kante mit ’gefundenem’ Nachfolger :
– Erforsche Kante, besuche Nachfolger und forsche von dort aus weiter bis es
nicht mehr weiter geht.
– Für jede Kante mit gefundenem Nachfolger:
– Kante überprüfen ohne den Knoten selbst zu besuchen.
– Knoten als ’abgeschlossen’ markieren.
⇒ Man erhält die Menge der vom Startknoten aus erreichbaren Knoten.
30
Elementare Graphenalgorithmen I
Graphendurchlauf
Tiefensuche – Beispiel (I)
KAPITEL 7. GRAPHENALGORITHMEN
A
D
A
B
F
B
G
E
C
F
Beginn der Tiefensuche
A
B
E
F
D
Tiefensuche – Beispiel
(II)
B
G
G
F
A
B
E
C
D ist eine Sackgasse
Backtracke und erforsche den nächsten Knoten
A
F
F
F
C
B
C
A
G
E
E
Elementare Graphenalgorithmen I
F
B
B
D
C
E
G
D
G
B
F
F
E
G
G
E
E
Erforsche den nächsten Knoten
D
GGraphendurchlauf
F
Beide nächsten Knoten wurden bereits gefunden
C
C
Datenstrukturen
A undBAlgorithmen
Tiefensuche – Implementierung
F
C
B
Erforsche den nächsten Knoten
Backtracke und Aerforsche den nächsten
KnotenA
D
A
D
A
C wurde bereits gefunden
Backtracke
und bereits
erforsche den
nächsten Knoten
C wurde
gefunden
Joost-Pieter Katoen
E
C
B ist eine Sackgasse
Backtracke und erforsche den nächsten Knoten
D
B
D
G
D
A
29/36
GraphendurchlaufB
G
Tiefensuche – Beispiel (III)
F
E
C
Nächster Zustand wurde bereits gefunden
Datenstrukturen
und Algorithmen
Backtracke
und erforsche
den nächsten Knoten
D
Elementare Graphenalgorithmen I
D
B
Nächster Zustand wurde bereits gefunden
Joost-Pieter Katoen
Backtracke und erforsche den nächsten Knoten
A
E
C
Graphendurchlauf
A
E
C
G
Sackgasse!
Backtracke und erforsche den nächsten Knoten
Erforsche einen Knoten
F
D
G
Elementare Graphenalgorithmen I
A
E
C
A
B
C
G
Erforsche einen Knoten
D
F
D
C
G
D
B
30/36
G
E
Fertig!
F
C
E
Beispiel
fürint
eine
Tiefensuche
BeidedfsRec(List
nächsten Knoten
wurden
bereits
gefunden
void
adjList[n],
n,
int start, Fertig!
int &color[n]) {
2
color[start] = GRAY;
3
foreach (next in adjList[start])
31 {
4
if (color[next] == WHITE) {
5
dfsSRec(adjList, n, next, color);
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
6
}
7
}
8
color[start] = BLACK;
9 }
1
31/36
KAPITEL 7. GRAPHENALGORITHMEN
2
4
6
void d f s S e a r c h ( L i s t a d j L i s t [ n ] , int n , int s t a r t ) {
int c o l o r [ n ] ;
fo r ( int i = 0 ; i < n ; i ++){
// F arbarray i n i t i a l i s i e r e n
c o l o r [ i ] = WHITE;
}
dfsRec ( adjList , n , s t a r t , c o l o r ) ;
}
8
10
12
14
16
void d f s R e c ( L i s t a d j L i s t [ n ] , int s t a r t , int &c o l o r [ n ] ) {
c o l o r [ s t a r t ] = GRAY;
// A k t u e l l b e t r a c h t e t e n Knoten grau f ä rben
f o r e a c h ( next i n a d j l i s t [ s t a r t ] ) {
i f ( c o l o r [ next ] == WHITE)
d f s R e c ( a d j L i s t , n , next , c o l o r ) ;
}
c o l o r [ s t a r t ] = BLACK; // Gefundenen S t a r t k n o t e n schwarz f ä rben
}
1.2 Breitensuche
Prinzip:
– Alle Knoten als ’nicht gefunden’ markieren
– Aktuell betrachteten Knoten als ’gefunden’ markieren
– Jede Kante mit ’nicht gefundenem’ Nachfolger:
– Gleichzeitig von allen diesen Knoten aus weiter suchen
→ Kein Backtracking
⇒ Man erhält die Menge aller Knoten, die vom Stratknoten aus erreichbar ist.
32
Elementare Graphenalgorithmen I
Graphendurchlauf
7. GRAPHENALGORITHMEN
Breitensuche KAPITEL
– Beispiel
A
D
B
F
C
A
A
E
F
C
C
G
E
Erforsche alle folgenden nicht-gefundenen Knoten
A
D
B
F
B
G
Beginn der Breitensuche
D
D
B
G
F
E
Erforsche alle folgenden nicht-gefundenen Knoten
C
G
E
Fertig!
Beispiel für eine Breitensuche
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
25/36
void b f s S e a r c h ( l i s t a d j l i s t ( n ) , int n , int s t a r t ) {
2
int c o l o r [ ] ;
Queue
w a i t ; //
ialisieren
Elementare Graphenalgorithmen
I Warteschlange i n i tGraphendurchlauf
4
// A l l e Knoten a l s ’ n i c h t gefunden ’ m a r k i e r e n
fo r ( int i = 0 ; i < n ; i ++)
6
c o l o r [ i ] = WHITE;
c o l o r [ s t a r t ] = GRAY; // S t a r t k n o t e n a l s ’ gefunden ’ m a r k i e r e n
I wKnoten
8
a i t . enqueue
( s t ain
r t der
) // SReihenfolge
t a r t k n o t e n amit
u f zunehmenden
Warteschlange Abstand
s e t z e n vom
werden
While
( ! Wait . isempty
()){
Startknoten
aus besucht.
10
int v = w a i t . dequeue ( ) ) ; // Knoten a l s b e a r b e i t e t von queue nehmen
I Nachdem alle Knoten mit Abstand d verarbeitet wurden, werden die
f o r e a c h (w i n a d j l i s t [ v ] ) { // Die N a c h f o l g e r k n o t e n von v b e t r a c h t e n
mit
12
i f dc o+l o1r angegangen.
[ w] == WHITE {
I Die Suche
c o l o r [terminiert,
w] = GRAY;wenn in Abstand d keine Knoten auftreten.
14
w a i t . enqueue (w ) ; // N a c h f o l g e r k n o t e n a l s nä c h s t e S t a r t k n o t e n
I Die Tiefe des Knotens v im Breitensuchbaum ist seine kürzeste
}
Kantendistanz
zum Startknoten.
16
}
}
I Die zu verarbeitenden Knoten werden als FIFO-Queue (first-in
18
c o l o r [ v ] = BLACK; // Gefundenen Knoten a l s ’ a b g e s c h l o s s e n ’ m a r k i e r e n
first-out) organisiert.
}
Eigenschaften der Breitensuche
Es gibt eine einzige „Verarbeitungsmöglichkeit“ für v , nämlich, wenn
es aus der Algorithmus
Queue entnommen wird.
2 Sharir’s
I
Theorem
(Komplexität
der Zusammenhangskomponenten.
Breitensuche)
Sharir’s Algorithmus
findet starke
Die Zeitkomplexität ist O(|V | + |E |), der Platzbedarf ⇥(|V |).
Joost-Pieter Katoen
33
Datenstrukturen und Algorithmen
27/36
7
}
void dfsSearch(List
adjL[n],
int n, int start, int &color[n]) {
KAPITEL
7. GRAPHENALGORITHMEN
10
color[start] = GRAY;
11
foreach (next in adjL[start]) {
Prinzipif (color[next] == WHITE) {
12
13
dfsSearch(adjL,
n, next, color);
– Tiefensuche
auf Graph
14
}– Alle Knoten, die ’abgeschlossen’ sind, also gefunden wurden, auf einem Stack
15
}
speichern.
16
color[start] = BLACK; // Schliesse ab
17 }– Graph transponieren und auf diesem transponierten Graphen eine weitere Tiefen9
suche durchführen. Dabei in der Reihenfolge die Knoten besuchen, in der sie auf
dem Stapel stehen.
Joost-Pieter
Katoen
– Leiter
Algorithmen
speichern. Leiter sind Knoten, dieDatenstrukturen
als erste beiundder
2. Tiefensuche ’entdeckt’10/33
wurden.
Elementare
Graphenalgorithmen
II
Starke
Zusammenhangskomponenten
⇒ Die
starken Zusammenhangskomponenten
sind
die im stapel zwischen
zwei Leitern.
Sharir’s
Algorithmus – Beispiel
Beispiel:
A
D
B
F
C
A
B
G
E
Ursprünglicher Digraph
E
G
A
F
B
D
C
Stack am Ende der Phase 1
D
F
C
G
E
Transponierter Graph
A
D
B
F
C
G
E
In Phase 2 gefundene starke Komponenten
Zeitkomplexität
Joost-Pieter Katoen
Algorithmen
Sharir’s Algorithmus hat eine ZeitkomplexitätDatenstrukturen
von Θ(|V | und
+ |E|).
Seine Speicherkomplexität beträgt: Θ(|V |).
3 Prims Algorithmus
Der Algorithmus findet minimale Spannbäume.
34
12/33
KAPITEL 7. GRAPHENALGORITHMEN
Prinzip
– Bei beliebigen Knoten beginnen, Wert dieses Knotens auf 0, den der anderen auf
∞ setzen.
– Günstigste Kante bestimmen (→ Greedy- Algorithmus), Werte der angrenzenden
Knoten updaten, wenn Kantengewicht kleiner als der Wert ist.
– Bei günstigem Knoten fortfahren, bis keine weiteren Randknoten mehr verfügbar
sind.
– Bei gleichem Gewicht wird in alphabetischer Reihenfolge vorgegangen.
4 Single Source Shortest Path (SSSP)
4.1 Dijkstra-Algorithmus
Dijkstra ermittelt die kürzesten Wege vom Startknoten zu allen anderen Knoten des
Graphen.
Hier sind (im Gegensatz zu Bellman Ford) ausschließlich nicht negative Kantengewichte
zugelassen.
– Initialisiere alle Knoten mit ∞
– Aktualisiere ausgehend vom aktuell betrachteten Knoten alle Knoten, die mit diesem verknüpft sind, wenn die Summe aus aktuellem Knoten und der Kante geringer
Lehrstuhl für Informatik 2
Datenstrukturen und Algorithmen SoSe 2012
ist als
der Wert des Zielknotens. Betrachte den
aktuellen Knoten
zukünftig nicht
Modellierung und Verifikation von Software
Musterlösung - Übung 11
mehr.
2
Die einzige starke Zusammenhangskomponente ist der gesamte (vollständige) Graph. Ihr Gesamtgewicht ist
– Fahre mit
dem
Knoten
mitdesminimalem
Wert
fort.
3. Somit
würde
das Verfahren
Studenten FALSE
ausgeben.
Es gibt jedoch einen Zyklus mit negativem
Gewicht von A nach B und zurück.
→ Greedy-Algorithmus
⇒ Führe diese Schritte in einer (großen) Tabelle aus (siehe Beispiel).
Beispiel
34
A
1
D
32
13
7
Schritt
Knoten
D[A]
D[B]
D[C]
D[D]
D[E]
D[F ]
D[G]
D[H]
D[I]
0
A
0
34
1
1
1
1
1
1
1
1
D
X
33
1
1
1
1
6
8
1
2
G
X
33
1
X
1
1
6
8
1
6
10
H
3
H
X
33
1
X
10
1
X
8
18
35
14
11
2
3
C
4
E
12
5
G
9
B
4
E
X
33
1
X
10
21
X
X
16
F
8
I
5
I
X
33
1
X
X
21
X
X
16
6
F
X
25
35
X
X
21
X
X
X
7
B
X
25
34
X
X
X
X
X
X
8
C
X
X
34
X
X
X
X
X
X
3
G
10
H
I
KAPITEL 7. GRAPHENALGORITHMEN
Schritt
Knoten
D[A]
D[B]
D[C]
D[D]
D[E]
D[F ]
D[G]
D[H]
D[I]
0
A
0
34
1
1
1
1
1
1
1
1
D
X
33
1
1
1
1
6
8
1
2
G
X
33
1
X
1
1
6
8
1
3
H
X
33
1
X
10
1
X
8
18
4
E
X
33
1
X
10
21
X
X
16
5
I
X
33
1
X
X
21
X
X
16
6
F
X
25
35
X
X
21
X
X
X
7
B
X
25
34
X
X
X
X
X
X
8
C
X
X
34
X
X
X
X
X
X
4.2D[H]
Bellman-Ford-Algorithmus
D[I]
Bellman Ford bestimmt den Kürzesten Pfad von einem Startknoten zu allen anderen
b)
Beweisen
Sie dem
die Korrektheit
des Dijkstra
d.h. zeigen
Sie, dass dieser Algorithmus für einen
Knoten
nach
SSSP (single
sourceAlgorithmus,
shortest path)Prinzip.
Graphen
G
den
kürzesten
Abstand
vom
Startknoten
s
zu
jedem
anderen
von s erreichbaren
Knoten in G
Wichtigster Unterschied zu Dijkstra ist, dass er auch mit negativen
Kantengewichten
berechnet.
Sie
dürfen
dazu
das
Theorem
aus
Vorlesung
17,
Folie
19
nutzen.
umgehen kann.
c) Beweisen oder widerlegen Sie die folgenden Aussagen für einen gewichteten, zusammenhängenden, ungerichteten Graphen G:
Prinzip
i) Der vom Dijkstra Algorithmus berechnete SSSP-Baum ist ein Spannbaum.
1. Initialisiere alle Knoten mit ∞
ii) Der vom Dijkstra Algorithmus berechnete SSSP-Baum ist ein minimaler Spannbaum.
2. Initialisiere den Startknoten mit 0
3. Aktualisiere die Kosten aller direkt durch Kanten erreichbaren Knoten, wenn durch
die Summe des Ursrungsknotens und 3der Kosten der Kante ein geringerer Wert
erzielt wird, als der Zielknoten bislang hatte.
4. Wiederhole 3), bis sich die Kosten nicht mehr ändern.
→ Breche ab, wenn ein negativer Zyklus vorliegt. Dies ist der Fall, wenn nach (Knotenanzahl - 1)- Wiederholungen noch Verbesserungen möglich sind.
⇒ Führe diese Schritte in einer Tabelle aus (siehe Beispiel).
36
Aufgabe 1 (Bellman-Ford
Algorithmus):
(5 + 6 + 3 = 14 Punkte)
KAPITEL
7. GRAPHENALGORITHMEN
a) Bestimmen Sie für den Startknoten A die Längen der kürzesten Wege zu jedem Knoten im unten gegebenen
Graphen G1 mit Hilfe des Bellman-Ford Algorithmus. Dabei sei die Reihenfolge der Knoten gegeben durch
Beispiel
die alphabetische Sortierung (A, B, C, . . . ). Geben Sie für jeden Knoten K die Kosten an, die dem Knoten
während der Berechnun zugewiesen werden. Z.B. im Format K : 1, 10, 7, 6, 3. Geben Sie außerdem an,
ob der Algorithmus einen Zyklus
Gewicht erkennt.
7
A
5
2
D
B
3
8
-4
1
E
6
1/A 1/B
C
A:
B:
C:
D:
E:
F:
1
F
1
1
1
1
1
1
1/E
1/F 2/B 2/F
0
7
6
15
4
3
2
5
3
2
A:
B:
C:
D:
E:
F:
1,
1,
1,
1,
1,
1,
0
7, 6
15, 4, 3
2
5
3, 2
Der Graph enthält keinen Zyklus mit negativem Gewicht.
b) Passen Sie die Implementierung von
haben (Vorlesung
17, Folie 13), so an, dass der kürzeste Pfad zwischen zwei Knoten i und j ausgegeben (nicht zurückgegeben!)
wird. Sie dürfen davon ausgehen, dass der übergebene Graph keine negativen Zykel besitzt.
g
Ihre Funktion soll die folgende Signatur haben:
5 Topologische Sortierung
Topologische Sortierung
bezeichnetadjLst[n],
eine Reihenfolge
Dingen,
bei der vorvoid bellFord(List
int n, intvon
i, int
j)
gegebene Abhängigkeiten erfüllt sind. Anstehende Tätigkeiten einer Person
Zuretwa
Ausgabe
können Sie annehmen,
dass eine Funktion
ausgabe mitBedingungen
folgender Signatur
unterliegen
einer Halbordnung:
es existieren
wieexistiert:
„Tätigkeit A muss vor Tätigkeit B erledigt werden“. Eine Reihenfolge, welche alle
void ausgabe(String text)
Bedingungen erfüllt, nennt man topologische Sortierung der Menge anstehenderkönnen
Tätigkeiten.
Einedass
Topologische
Sortierung
nur konvertiert
möglich, werden
wenn können.
es
Außerdem
Sie annehmen,
int-Werte automatisch
nachist
String
keinen Zyklus gibt, d.h. wenn keine gegenseitigen Abhängigkeiten vorliegen.
c) Einem Studenten gefällt die Laufzeit des Bellman-Ford Algorithmus nicht und er schlägt das folgende
alternative Verfahren vor, um Zyklen mit negativem Gesamtgewicht zu erkennen:
WirPrinzip:
benutzen Sharirs Algorithmus, um alle starken Zusammenhangskomponenten zu finden. Dies kostet
O(|V | + |E|). Da |E| 2 O(|V |2 ) sind die Kosten damit in O(|V | + |V |2 ) = O(|V |2 ). Für jede starke Zusammenhangskomponente berechnen wir dann die Summe der Gewichte ihrer Kanten. Dies kostet insgesamt
– Stelle die Abhängigkeiten als Graph dar.
O(|E|) und ist also wiederum in O(|V |2 ). Ist eine dieser Summen negativ, geben wir TRUE aus, sonst
FALSE.
– Die gerichteten Kanten zeigen jeweils zum Knoten, von dem der
Ausgangsknoten
ist
Wo liegt der Fehler,
den der Studentabhängig
begangen hat?
– Sortiere die Knoten nach ihrer Abhängigkeiten so dass rechts diejenigen
Knoten stehen, von denen nichts abhängt und links diejenigen Knoten
stehen, die keine eigenen Abhängigkeiten haben
– Versehe alle Knoten mit den jeweiligen Kosten.
1
⇒ Der Kritische Pfad ist der Pfad mit den maximalen Kosten (betrachtet
von links nach rechts).
Der kritische Pfad ist eine Folge von Aufgaben v0 . . . vk , sodass
- v0 keine Abhängigkeiten hat
- vi abhängig von vi−1 ist, wobei est(vi ) = ef t(vi−1 ) (Keine Verzögerung!)
est: earliest starting-time
37
KAPITEL 7. GRAPHENALGORITHMEN
eft: earliest finish-time
- ef t(vk ) das Maximum über alle Aufgaben ergibt.
Beispiel
Arbeitsschritt
Vorlesung
Folien
Lehrstoff
Globalübung
Musterlösung
Aufgaben
Blatt
Tutorenbesprechung
Abkürzung
V
F
L
G
M
A
B
T
Dauer
1
4
1
1
2
3
1
1
Abhängig von
F
L
A, M
A
L
A
A, M
L
F
V
A
M
G
B
1
4
1
3
2
1
1
T
Darstellung der Abhängigkeiten als gerichteter Graph und als Topologische Sortierung
mit kritischem Pfad.
– Vollständige Tiefensuche, bei der zusätzlich ein Array ’kritische Länge’
und ’earliest finish-time’ übergeben wird.
– Nach der Abfrage der Knotenfarbe wird jedes mal folgende Abfrage
durchgeführt:
1
3
i f ( e f t [ next ] >= e s t ) {
e s t = e f t [ next ]
c r i t D e p [ s t a r t ] = next ;
38
yd
All-Pairs Shortest Path
Der Algorithmus von Floyd
All-Pairs Shortest Paths
KAPITEL 7. GRAPHENALGORITHMEN
Wir betrachten gewichtete Digraphen G = (V , E , W ).
I
I
Die Funktion W ordnet Kanten ein Gewicht zu.
}Negative Gewichte sind zugelassen, aber keine Zyklen mit negativem
Gewicht.
– Bevor Ider
Knoten
schwarz
gefärbt
wird, wird
Nicht
vorhandene
Kanten
haben Gewicht
W (·, ·) = Œ.
e f t [ s t a r t ] = est + duration [ s t a r t ]
Problem (All-Pairs Shortest Path)
Berechne für jedes Paar i, j die Länge D[i,j] des kürzesten Pfades.
durchgeführt.
Naive Lösung: lasse ein SSSP-Algorithmus (z. B. Bellman-Ford) |V | mal
laufen. Dies führt zu einer Worst-Case Zeitkomplexität O(|V |4 ).
Floyd’s Algorithmus.
6 All Effizientere
Pairs Version:
Shortest
Paths
orithmen
17/22
yd
Betrachtet
wird die Länge des Pfades jedes
Knotens mit jedem anderen
KnoJoost-Pieter Katoen
Datenstrukturen und Algorithmen
18/22
ten. Hier sind negative Kantengewichte, jedoch keine negativen Zyklen zugelassen.All-Pairs Shortest Path
Der Algorithmus von Floyd
Der Algorithmus von Floyd – Idee
35
6.1 Floyd-Warshall Algorithmus
j
.,k
i
Prinzip
j
10
™{
1}
Verbessert sich die Pfadlänge,
wenn der Weg über Zwischenknoten
führt?
1, .
, k≠
}
≠1
..,
Rekursionsgleichung:
k≠
,..
I
Vorgehen wie bei Warshall, jedoch mit folgender Rekursionsgleichung:
Y
] W (i, j)
(k)
1
2
dij =
[ min d (k≠1) , d (k≠1) + d (k≠1)
für k > 0
ij
(statt: tij
(k≠1)
D[i,j] = dij .
(·)
I
19/22
.
1
1}
– Floyd-Warshall ist eine klassische
k Aufgabe
™ { der Dynamischen Programmierung:
für k = 0
orithmen
25
‚
1
ik
tik
(k≠1)
kj
· tkj
(k≠1)
2
für k = 0
für k > 0
)
Auch hier arbeiten wir direkt im Ausgabearray: D[i,j] = dij .
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
39
(·)
19/22
• Namen und Matrikelnummern der Studenten sowie die Nummer der Übungsgruppe sind auf jedes Blatt der
Abgabe zu schreiben. Heften bzw. tackern Sie die Blätter!
KAPITEL 7. GRAPHENALGORITHMEN
Aufgabe 1 (Floyd-Algorithmus):
(8 Punkte)
Bestimmen Sie für den folgenden Graphen die Werte der kürzesten Pfade zwischen allen Paaren von Knoten.
Nutzen Sie hierzu den Algorithmus von Floyd. Geben Sie das Distanzarray vor dem Aufruf, sowie nach jeder
Iteration an.
Die Knotenreihenfolge sei mit A, B, C, D, E fest vorgegeben.
Beispiel
3
D
A
6
3
5
8
7
7
C
4
2
9
1
E
B
9
A
B
C
D
E
A
B
C
D
E
A B C
0 7 1
8 0 9
5 1 0
6 1 3
1 9 1
D E
3 1
1 1
1 2
0 4
7 0
A B C D
0
7 16 3
8
0
9 11
5 12 0
8
6 13 3
0
17 9 18 7
E
8
1
2
4
0
A
B
C
D
E
A
B
C
D
E
A B C D
0 7 1 3
8 0
9 11
5 12 0 8
6 13 3 0
1 9 1 7
A B
0
7
8
0
5 12
6 13
13 9
C
6
9
0
3
10
E
1
1
2
4
0
A
B
C
D
E
A
0
8
5
6
17
B C
7 16
0
9
12 0
13 3
9 18
D E
3 7
11 1
8 2
0 4
7 0
A
B
C
D
E
A B
0
7
8
0
5 11
6 13
13 9
C
6
9
0
3
10
D E
3 8
11 1
8 2
0 4
7 0
D E
3 7
8 1
8 2
0 4
7 0
.
7 Algorithmen auf Flussnetzwerken
1
7.1 Ford-Fulkerson-Methode - Maximaler Fluss
Prinzip
– Überführe den Graphen in ein Flussnetzwerk.
– Suche einen beliebigen Pfad zwischen s und t heraus.
– Bestimme die minimale Kapazität (maximalen Durchfluss) dieses
Pfades.
– Bestimme die Flusserhöhung, indem der Fluss entlang des Pfades
gleich der Kapazität der Kante mit der minimalen Kapazität gesetzt
wird.
– Bilde das Restnetzwerk, indem der Durchfluss als umgekehrte Kanten eingezeichnet wird (eventuell existierende Gegenpfade werden
verrechnet).
40
Maximaler Fluss
Ford-Fulkerson-Methode
KAPITEL 7. GRAPHENALGORITHMEN
Schnitte– Fahre
in Flussnetzwerken
solange fort, neue Pfade zu suchen, bis es keine augmentierende
Definition
(den Fluss weiter vergrößernde) Pfade mehr gibt, d.h. die Senke noch
von der Quelle aus erreichbar ist.
→ Der Maximale Fluss ist die Summe aller Flusserhöhungen.
Ein Schnitt (S, T ) in einem Flussnetzwerk G = (V , E , c) ist eine Partition
S fi T = V , S fl T = ? mit s œ S und t œ T .
7.2 Min-cut-max-flow
I
Wenn f ein Fluss in G ist, dann ist f (S, T ) der Fluss über (S, T ).
I
DieSKapazität
c(S,
∪Schnitte
T = V, S ∩von
∅(S,
mitTs)∈ist
S und
t ∈TT ).
. Die Knoten werden also in zwei
inT 6=Netzwerken
I
Datenstrukturen und Algorithmen
(Folie 366, Seite 62 im Skript)
Ein Schnitt (S, T) in einem Flussnetzwerk G = (V, E, c) ist eine Partition
aufgeteilt: Eine, die die Senke- und eine, welche die Quelle enthält.
Ein Gruppen
minimaler
Schnitt ist ein Schnitt mit minimaler Kapazität.
12/12
v1
v3
11/16
s
8/13
Joost-Pieter Katoen
15/20
1/4
10
v2
4/9
11/14
7/7
v4
t
4/4
(Schnitt
Der Fluß über
(S, T(S) =
ist/s,
19.v1 , v2 /, T = /t, v3 , v4 /) hier 26)
Datenstrukturen und Algorithmen
Die Kapazität von (S, T ) ist 26.
Max-flow Min-cut Theorem
Ist f ein Fluss im Flussnetzwerk G, dann sind äquivalent (gleichbedeutend):
– f ist ein maximaler Fluss.
– In Gf gibt es keinen augmentierenden Pfad.
– |f | = c(S, T ) für einen Schnitt (S, T ), d.h. der Schnitt (S, T ) ist minimal.
Daraus folgt:
→ Die Kapazität eines minimalen Schnittes ist gleich dem Wert eines maximalen Flusses. (Kapazität des minimalen Schnittes entspricht dem
maximalen Flusses)
→ Falls die Ford–Fulkerson–Methode terminiert, berechnet sie einen maximalen Fluss.
41
37/42
8
Hashing
Allgemeines Prinzip
Das Ziel von Hashing ist es, einen großen Schlüsselraum auf einen kleineren
Bereich von ganzen Zahlen abzubilden. Dabei soll möglichst unwahrscheinlich
sein, dass zwei Schlüssel auf die selbe Zahl abgebildet werden. Eine Hashfunktion bildet einen Schlüssel auf einen Index der Hashtabelle T ab:
h : U → {0, 1, ..., m − 1} für Tabellengröße m und |U | = n.
Wir sagen,
dass h(k) der Hashwert des
Schlüssels k ist. Das Auftreten von
Hashing I
Grundlagen des Hashings
0
0
h (k) für k 6= k nennt man Kollision.
Hashing (II)
Schlüsselmenge
Hashfunktion
U
k2
k4
K
0 Hashtabelle
h(k1 )
h(k2 ) = h(k3 )
k1
Kollision
h(k4 )
m≠1
benutzte Schlüssel
I
Das liegt am
I
Die Wahrscheinli
Geburtstag hat is
I
Fragt man 23 Pe
23
365 ¥ 0,063.
I
Sind aber 23 Per
den selben Gebur
Wie finden wir Hashfunktionen, die einfach auszurechnen sind und
Kollisionen minimieren?
Wie behandeln wir dennoch auftretende Kollisionen?
1 Hashfunktionen
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Hashing I
Grundlagen des Hashings
1
15/35
Eine Hashfunktion bildet einen Schlüssel auf einen Index (eine ganze Zahl)
Kollisionen: Das Geburtstagsparadoxon (II)
ab.
Gute Hashfunktionen
Auf Hashing angewendet bedeutet das:
I
Unsere
wir so
Die Wahrscheinlichkeit keiner Kollision nach k Einfügevorgängen in
Eine gute Hashfunktion
ist charakterisiert
durch folgende Eigenschaften:
einer m-elementigen
Tabelle ist:
≠1
m m≠1
m ≠ k + 1 kŸ
m≠i
·
· ... ·
=
m
m
m
m
i =0
42
I
Dieses Produkt geht gegen 0.
I
Etwa bei m = 365 ist die Wahrscheinlichkeit für k > 50 praktisch 0.
Joost-Pieter Katoen
Hashing I
Kollisionen: Das
1.0
Wahrscheinlichkeit
keiner Kollision
I
Kollisionen: Das
Geburtstagsparadox
h(k5 )
k3
k5
Hashing I
0.8
0.6
0.4
0.2
KAPITEL 8. HASHING
– Effizient
– Geringer Speicheraufwand
– Einfach zu berechnen
– Eingabewerte müssen nur einmal ausgelesen werden
– Ähnliche Schlüssel sollten zu unterschiedlichen und breit verteilten Hashwerten führen.
– Die Hashfunktion sollte surjektiv sein, d.h möglichst jeder Hashwert
sollte genutzt werden.
– Dabei sollte alle Indizes in etwa die gleiche Häufigkeit besitzen.
Es gibt verschiedene Methoden, um eine gute Hashfunktion zu erhalten:
– Divisionsmethode: Hashfunktion: h(k) = k mod m
– Dabei sollte m möglichst eine Primzahl sein und nicht zu nahe an
einer Zweierpotenz liegen.
– Multiplikationsmethode: Hashfunktion: h(k) = bm(k · c mod 1)c
für 0 < c < 1
k ·c mod 1 ist hierbei der Nachkommateil von k ·c, d.h. k ·c−bk ·cc.
– Universelles Hashing: Löst das Problem, dass es immer eine ungünstige Sequenz von Schlüsseln geben kann, sodass alle Schlüssel auf einen
Hashwert abgebildet werden.
– Dazu wird beim universellen Hashing eine zufällige Hashfunktion
aus einem Pool H von Hashfunktionen ausgewählt.
– Eine Menge H der Hashfunktionen wird als universell betrachtet,
wenn mit einer zufällig aus H ausgewählten Hashfunktion die Wahrscheinlichkeit für eine Kollision zwischen den Schlüsseln k und l
nicht größer als die Wahrscheinlichkeit m1 einer Kollision ist, wenn
h(k) und h(l) zufällig und unabhängig aus der Menge {0, 1, ..., m −
1} gewählt wurden.
– Für universelles Hashing ist die erwartete Länge der Liste T [k]
- gleich α, wenn k nicht in T enthalten ist.
- gleich 1 + α, wenn k in T enthalten ist.
2 Geschlossenes Hashing
Beim geschlossenen Hashing, auch Kollisionsauflösung durch Verkettung genannt, werden alle Schlüssel, die zum gleichen Hashwert führen, innerhalb
einer verketteten Liste gespeichert, auf die ein Arrayeintrag verweist:
43
hmen
Kollisionsauflösung durch Verkettung (I)
Idee
KAPITEL
8. führen,
HASHING
Alle Schlüssel, die zum
gleichen Hash
werden in einer
verketteten Liste gespeichert.
k2
k4
k1
k7
k3 k
6
k5
k1
k2
k3
k6
k7
k5
k4
m≠1
19/35
II)
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Hashing I
Verkettung
Idee der Kollisionsauflösung durch Verkettung
20/35
Kollisionsauflösung durch Verkettung (III)
Komplexität
– Im Worst-Case
Worst-Case
haben alle Schlüssel den selben Hashwert. Suchen und
Komplexität
Löschen
hat
die
selbe
Worst-Case
wieetwa
bei⇥(1).
Listen: W (n) =
Angenommen, die Berechnung
von h(k)Komplexität
ist recht effizient,
Θ(n).
Die Komplexität ist:
Suche: Proportional
zurbeträgt
Länge derdie
Liste
T [h(k)]. zum (erfolgreichen und
– Im Average-Case
jedoch
Laufzeit
Einfügen:Suchen
Konstant
(ohne=Überprüfung,
erfolglosen)
A(n)
Θ(1 + α). ob das Element schon
vorhanden ist).
n
(n: Anzahl der eingeα ist hierbei der Füllgrad der Hashtabelle: α = m
Löschen: Proportional zur Länge der Liste T [h(k)].
gebenen Schlüssel, m: Größe der Hashtabelle)
Schlüssel k in der
fang der Liste
Liste T[h(e.key)].
hmen
0
U
K
[Luhn 1953]
I
Im Worst-Case haben alle Schüssel den selben Hashwert.
I
Suche und Löschen hat dann die selbe Worst-Case Komplexität wie
Listen: ⇥(n).
I Im Average-Case
ist Hashing mit Verkettung aber dennoch effizient!
3 Offenes
Hashing
21/35
Joost-Pieter Katoen
Allgemeines Prinzip:
Datenstrukturen und Algorithmen
22/35
Beim offenen Hashing, auch Hashing mit offener Adressierung genannt, werden alle Schlüssel direkt auf eine einzige Hashtabelle abgebildet. Dabei können höchstens n Schlüssel gespeichert werden:
α(n, m) =
n
≤1
m
Einfügen eines Schlüssels k
– Sondiere die Positionen der Hashtabelle, bis ein leerer Slot gefunden
wird
– Die zu überprüfenden Positionen werden mittels einer Sondierungsfunktion in Abhängigkeit des Schlüssels k bestimmt.
44
KAPITEL 8. HASHING
Die Hashfunktion hängt also sowohl vom Schlüssel k, als auch
von der Nummer der Sondierung i ab.
Sondierungsfunktionen
Sondierungsfunktionen ordnen einen Schlüssel k auf eine Position der Hashtabelle zu. Dazu wird bei jeder fehlgeschlagenen Zuordnung eines Schlüssels
dessen Zähler i um 1 hochgesetzt und die Sondierungsfunktion mit diesen
modifizierten Parametern erneut aufgerufen.
– Lineares Sondieren: h(k, i) = (h0 (k) + i) mod m (für i < m)
mit: k: Schlüssel
i: Sondierungsschritt
h’: Hashfunktion
– Die Verschiebung der nachfolgende Sondierungen ist linear von i
abhängig, die erste Sondierung bestimmt bereits die gesamte Sequenz.
→ Es können insgesamt m verschiedene Sequenzen erzeugt werden.
– Quadratisches Sondieren: h(k, i) = (H 0 (k) + c1 · i + c2 · i2 ) mod m
(für i < m)
mit: k: Schlüssel
i: Sondierungsschritt
h’: Hashfunktion
Konstanten c1 , c2 6= 0
– Die Verschiebung der nachfolgende Sondierungen ist quadratisch
von i abhängig, die erste Sondierung bestimmt auch hier bereits die
gesamte Sequenz.
→ Bei geeignet gewähltem c1 , c2 können auch hier insgesamt m
verschiedene Sequenzen erzeugt werden.
→ Clustering (Aneinanderreihung), welches bei linearem Sondieren auftritt wird jedoch vermieden. Jedoch tritt sekundäres
Clustering immer noch auf:
Beispiel: h(k, 0) = h(k 0 , 0) verursacht h(k, i) = h(k 0 , i) (für
alle i)
– Doppeltes Hashing: h(k, i) = (h1 (k) + i · h2 (k)) mod m (für i <
m)
mit: h1 , h2 : Übliche Hashfunktionen.
45
20/1
22/1
h1 (k) = k mod 11
h2 (k) = 1 + k mod 10
h(k, i) = (h1 (k) + i · h2 (k)) mod 11
KAPITEL 8. HASHING
Joost-Pieter Katoen
Hashing II
Datenstrukturen und Algorithmen
21/1
- Die Verschiebung der nachfolgenden Sondierungen ist von h2 (k)
abhängig. Die erste Sondierung bestimmt also nicht die gesamte
Offene Adressierung
Sequenz.
Dies führt zu einer besseren Verteilung der Schlüssel in der
Praktische→Effizienz
von Doppeltem Hashing
Hashtabelle. Dies kommt gleichverteiltem Hashing nahe.
I
I
Hashtabelle- mit
051 m
Einträgen
(Endfüllgrad
99,95%)
358
Sind538
h2 und
relativ prim
(Teilerfremd),
wird99,8
die% ->
gesamte
Hashtabelle
abgesucht.
Mittlere Anzahl
Kollisionen
÷ pro Einfügen in die Hashtabelle:
14
Lineares Sondieren
Quadratisches Sondieren
Doppeltes Hashing
12
10
÷
8
6
4
2
0
0
10
20
30
40
50
60
70
80
90 100
Füllgrad der Hashtabelle (in %)
Vergleich der drei Sondierungsmethoden
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
23/1
Komplexität
Average-Case:
– Die erfolgreiche Suche benötigt O
1
α
1
– Die erfolglose Suche benötigt O( 1−α
)
1
· ln 1−α
Löschen eines Schlüssels k
Problematik
Im Gegensatz zum Geschlossenen Hashing kann ein zu löschender Schlüssel
hier nicht einfach gelöscht (durch null ersetzt) werden, da ansonsten das
beim Einfügen geschehene Sondieren nicht berücksichtigt wird.
Daher muss hier statt einem Löschen (ersetzen mit null ) der Schlüssel durch
einen speziellen Wert DELETED ersetzt werden.
46
9
Algorithmische Geometrie
Algorithmische Geometrie
Algorithmische Geometrie
Winkelbestimmung
1 Mathematische(III)
Grundlagen
Problem
Winkelbestimmung mit Determinanten
Gegeben der Streckenzug (p, q, r). Wird bei q nach links oder rechts
Gegeben der
Streckenzug
(p, q, r): ]pqr > 180¶ oder < 180¶ ?
abgebogen?
Oder:
Ist der Winkel
qr
r
x2
q
pq
p
I
I
I
I
˛b
˛a
–
]pqr = 180¶ +–
x1
−
→
→
− Determinante.
−
→
−
Wir
verwenden
wieder
– →
a = dpq = q −
p und die
b = dpr = r − q
−q ≠ p und ˛
Dazu berechnen wir ˛a = ˛dpq→
=→
b = ˛dqr = r ≠ q.
– Linksdrehung, wenn det(−
a, b)>0
det(˛a, ˛b) > 0, falls der Knick→
nach
→
− links geht (]pqr > 180¶ , – > 0).
−
– Rechtsdrehung, wenn det( a , b ) < 0
Wenn r auf (der
a, ˛b) =◦ 0
→
−Verlängerung von) pq liegt, dann ist det(˛
→
−
– Wenn det(
a , b ) = 0 liegt
(]pqr
= 0¶◦ oder
= 180¶ ). r auf der Verlängerung von pq. (]pqr = 0
oder 180 )
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Algorithmische Geometrie
Konvexe Hülle
Polygone
Polygone
Algorithmische Geometrie
Algorithmische Geometrie
Schnitt zweier Strecken
Problem
Gegeben zwei Strecken pq und rs. Schneiden sich diese?
nicht einfach
einfach
nicht konvex
konvex, einfach
q
r
Ein Polygon heißt einfach, wenn es sich nicht selbst schneidet.
konvex
26/33
p
47
s
Ein Polygon heißt konvex, wenn jede Verbindung (Konvexkombination)
zweier Punkte des Polygons nie außerhalb des Polygons liegt.
I
Wir sind nicht an der Position des Schnittpunktes interessiert.
I
Idee:Joost-Pieter
Wir Katoen
testen, ob die EndpunkteDatenstrukturen
r und sundauf
verschiedenen 27/33
Seiten
Algorithmen
10/33
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
KAPITEL 9. ALGORITHMISCHE GEOMETRIE
Algorithmische Geometrie
26/33
Konvexe Hülle
Konvexe Hülle
Konvexe Hülle
p11
p6
p5
p12
p0
p4
p1
p8
p2
p3
p9
p7
p10
Konvexe Hülle
konvexeHülle
Hülle einer
einer Menge
Punkten
ist das
konvexe
PoDieDie
konvexe
MengeQQvonvon
Punkten
ist kleinste
das kleinste
konvexe
lygon P, für das sich jeder Punkt in Q entweder auf dem Rand von P oder in
Polygon P, für das sich jeder Punkt in Q entweder auf dem Rand von P
seinem Inneren befindet. Hilfreich ist hierbei die Vorstellung der Punktemenoder
Inneren
befindet.
ge in
als seinem
Nägel auf
einem Brett,
um die außen ein Gummiband gespannt wird.
Die konvexe Hülle hat dann die Form, die durch das straffe Gummiband
Betrachte
jeden
als Nagel, der aus einem Brett herausragt.
gebildet
wird, das
allePunkt
Nägel umschließt.
I
I
Die konvexe Hülle hat dann die Form, die durch ein straffes
Gummiband gebildet wird, das alle Nägel umschließt.
2 Graham-Scan
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Der Graham-Scan gibt die konvexe Hülle einer Menge Q von Punkten in
einem zweidimensionalen Raum aus.
Prinzip
1. Suche den Startpunkt, der auf jeden Fall auf der Hülle liegt.
– Konvention: Gewählt wird der Punkt mit der niedrigsten x2 - Koordinate. Haben mehrere Punkte die gleiche x2 -Koordinate, so GIBT
zusätzlich die geringste x1 -Koordinate den Ausschlag
2. Von Punkt diesem ausgehend sortiere die Punkte nach zunehmendem
(Polar-) Winkel zur x1 - Achse (entspricht einer rotierenden Sweepline):
– Dies geschieht mittels Determinantenberechnung: Die Determinanten der Strecken vom Startpunkt zum betrachteten Punkt und
der x1 -Achse werden berechnet. Die Reihenfolge der Determinanten
gibt die Polarwinkelreihenfolge an.
48
28/33
KAPITEL 9. ALGORITHMISCHE GEOMETRIE
ülle
Algorithmische Geometrie
– Beispiel
Konvexe Hülle
Konvexe Hülle – Graham-Scan – Beispiel
p9
p6
p8
p7
p2
p8
p9
p3
p5
p4
p3
p2
p7
p1
p0
uren und Algorithmen
30/33
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
30/33
3. Die ersten drei Punkte werden nun auf einen Stapel gelegt (und somit
als ’aufKonvexe
der konvexen
liegend’ betrachtet).
Hülle –Hülle
Graham-Scan
– Beispiel
ülle
Algorithmische Geometrie
– Beispiel
Konvexe Hülle
4. Die weiteren Punkte werden
einzeln auf ihren Winkel zu den beiden
p9
Vorgängerpunkten auf dem Stapel überprüft:
– Die Winkelüberprüfung geschieht mittels Determinante:
p5
p6
p10
p5
p7
det(stack.top − (stack.top
− 1), N euesElement − stack.top)
p4
p8
p3
p2
uren und Algorithmen
p4
p
3
p11 die Determinante von (oberstem Stackelement ab→ Es pwird
also
12
züglich zweitoberstem Stackelement) und (neu hinzukommendem Element abzüglich oberstem Stackelement)
berechnet.
p2
p1
p1
– Hier sind zwei Fälle möglich:
30/33
p0
a) Ist die berechnete
Determinante ≤ 0, knickt die Verbindungsstrecke der drei Punkte bei Stack.top nach rechts ab. Das oberste Stapelelement wird entfernt, da es sich nicht auf der Hülle,
sondern im inneren des Polygons befindet.
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
30/33
– Das neu hinzukommende Element wird nun erneut mit den
restlichen auf dem Stack befindlichen Elementen überprüft.
b) Ist die berechnete Determinante > 0, knickt die Verbindungsstrecke der drei Punkte bei Stack.top nach links ab. Das neu
hinzukommende Element wird oben auf den bestehenden Stapel gelegt.
49
KAPITEL 9. ALGORITHMISCHE GEOMETRIE
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Algorithmische Geometrie
30/33
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Konvexe Hülle
lle
p9
p9
p6
p6
p5
p7
p8
p7
p4
p8
p3
p2
p5
p4
p3
p2
p1
p4
p2
p1
Datenstrukturen und Algorithmen
30/33
Joos
uren und Algorithmen
Rot: p7 wird aus konvexer Hülle entfernt, Grün: p8 wird anschließend überprüft.
Beispiel
2
Konvexe Hülle für folgende Punkte in einem Zweidimensionalen KoordinaDatenstrukturen und Algorithmen SoSe 2012, Fragestunde 29.08.2012
tensystem:
Lösung
(1, 0); (4, 1); (4, 3); (3, 3); (2, 2); (1, 4); (0, 2)
Knoten
Vektoren und Determinante
(3, 3)
✓
◆ ✓
◆
0
1
det(
,
)=0+2=2>0
2
0
(4, 3)
(4, 1)
(2, 2)
(3, 3)
(4, 3)
(1, 4)
(2, 2)
(3, 3)
✓
det(
✓
det(
1
0
1
1
◆ ✓
,
◆ ✓
,
1
2
1
1
◆
◆
)=
)=1
Stack
0=1>0
2
1=
30
1
0=
10
(3, 3)
(4, 3)
(4, 1)
(1, 0)
(2, 2)
(3, 3)
(4, 3)
(4, 1)
(1, 0)
(3, 3)
(4, 3)
(4, 1)
(1, 0)
50
(1, 4)
(3, 3)
(4, 3)
p
p0
p0
Joost-Pieter Katoen
p5
✓
det(
1
0
◆ ✓
,
2
1
◆
)=
(4, 3)
(4, 1)
p1
(2, 2)
(3, 3)
✓
det(
Knoten
(1, 4)
(2, 2)
(3, 3)
(1, 4)
(3, 3)
(4, 3)
(1, 4)
(4, 3)
(4, 1)
(0, 2)
(1, 4)
(4, 3)
◆ ✓
,
◆
1
1
KAPITEL 9. ALGORITHMISCHE
GEOMETRIE
0
1
)=1
0=1>0
Vektoren und Determinante
Stack
✓
det(
1
1
◆ ✓
,
1
2
◆
2
1=
30
✓
det(
1
0
◆ ✓
,
2
1
◆
1
0=
10
)=
)=
✓
◆ ✓
◆
0
3
det(
,
)=0+6=6>0
2
1
✓
det(
3
1
◆ ✓
,
1
2
4
51
◆
(2, 2)
(3, 3)
(4, 3)
)=6+1=7>0
(3, 3)
(4, 3)
(4, 1)
(1, 0)
(4, 3)
(4, 1)
(1, 0)
(1, 4)
(4, 3)
(4, 1)
(1, 0)
(0, 2)
(1, 4)
(4, 3)
(4, 1)
(1, 0)
Herunterladen