Algorithmen und Datenstrukturen

Werbung
Algorithmen und Datenstrukturen
Werner Struckmann
Wintersemester 2005/06
8. Graphen
8.1 Mathematische Grundlagen
8.2 Darstellung von Graphen
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
8.4 Ausgewählte Algorithmen für gewichtete Graphen
Einführung
Knoten
Ein Graph besteht aus Knoten (vertices
oder nodes), die durch Kanten (edges)
verbunden sind. Die Kanten können
◮
ungerichtet oder
◮
gerichtet
sein. Die entsprechenden Graphen heißen
ungerichtete bzw. gerichtete Graphen.
Kante
1
1
6
8
3
5
3
2
Gewicht
3
Zyklus
Ungerichteter
gewichteter
zyklischer Graph
Graphen, deren Kanten durch eine Zahl
gewichtet sind, nennt man gewichtete
Graphen.
Graphen können Zyklen enthalten.
Gerichteter
azyklischer Graph
8.1 Mathematische Grundlagen
8-1
Einführung
Knoten können durch eine Kante mit sich selbst verknüpft sein
(Schlinge).
ungerichteter zyklischer Graph mit Schlingen
Knoten können Attribute (zum Beispiel einen Wert oder eine
Farbe) besitzen.
gerichteter azyklischer gefärbter Graph
8.1 Mathematische Grundlagen
8-2
Anwendungsbeispiele
Ungerichtete Graphen:
◮
Kommunikationsnetz
◮
◮
Gewichte als Dauer einer Datenübertragung. Gesucht ist der
schnellste Übertragungsweg von a nach b .
Gewichte als Kosten einer Datenübertragung. Gesucht ist der
günstigste Übertragungsweg von a nach b .
Gerichtete Graphen:
◮
Straßennetz
◮
◮
Gewicht als Länge einer Wegstrecke. Gesucht ist die kürzeste
Strecke von a nach b .
Begriffsmodellierung, semantische Netze
◮
Unterbegriffe: ein „Auto“ ist ein „Fahrzeug“.
8.1 Mathematische Grundlagen
8-3
Anwendungsbeispiele
Gerichtete Graphen:
◮
Kontrollfluss in Programmen
◮
Welche Programmabschnitte werden bei gegebener Eingabe
nicht ausgeführt?
Gerichtete azyklische Graphen:
◮
Stammbäume
◮
◮
Gesucht sind die Vorfahren von x .
Vererbungshierachie in der objektorientierten
Programmierung
8.1 Mathematische Grundlagen
8-4
Gerichtete und ungerichtete Graphen
◮
Ein gerichteter Graph (Digraph) G ist ein Paar (V , E ) mit:
◮
◮
◮
◮
V ist eine endliche Menge (Knoten, Knotenmenge).
E ⊆ V × V ist eine Relation auf V (Kanten, Kantenmenge).
Eine Kante (u, u) ∈ E heißt Schlinge.
Ein ungerichteter Graph G ist ein Paar (V , E ) mit:
◮
◮
◮
◮
◮
V ist eine endliche Menge (Knoten, Knotenmenge).
E ⊆ {{u, v } | u, v ∈ V } ist eine Menge, deren Elemente einoder zweielementige Teilmengen von V sind. (Kanten,
Kantenmenge).
Eine einelementige Teilmenge {u} heißt Schlinge.
E kann als symmetrische Relation E ⊆ V × V angesehen
werden.
Man schreibt häufig (u, v ) ∈ E statt {u, v } ∈ E .
8.1 Mathematische Grundlagen
8-5
Adjazenz
Es sei ein gerichteter oder ungerichteter Graph G = (V , E )
gegeben. Falls (u, v ) ∈ E ist sagt bzw. schreibt man:
◮
(u, v ) tritt aus u aus,
◮
(u, v ) tritt in v ein,
◮
u und v sind adjazent (benachbart),
◮
u → v.
E ist die Adjazenzrelation.
8.1 Mathematische Grundlagen
8-6
Grad eines Knotens
Ungerichteter Graph:
◮
Der Grad eines Knotens ist die Anzahl der mit ihm in Relation
stehenden Knoten.
◮
Ein Knoten mit dem Grad 0 heißt isoliert.
Gerichteter Graph:
◮
Der Ausgangsgrad eines Knotens ist die Anzahl seiner
austretenden Kanten.
◮
Der Eingangsgrad eines Knotens ist die Anzahl seiner
eintretenden Kanten.
◮
Der Grad eines Knotens ist die Summe aus Ausgangs- und
Eingangsgrad.
8.1 Mathematische Grundlagen
8-7
Pfade
Es sei ein Graph G = (V , E ) gegeben.
◮
Ein Pfad p der Länge k in G von u ∈ V zu u′ ∈ V ist eine
Folge p = (v0 , v1 , . . . , vk ) von Knoten mit u = v0 , u′ = vk und
(vi −1 , vi ) ∈ E , i = 1, . . . k .
◮
Der Pfad p enthält die Knoten v0 , v1 , . . . , vk und die Kanten
(v0 , v1 ),. . . ,(vk −1 , vk ).
◮
Wenn es einen Pfad p von u ∈ V zu u′ ∈ V gibt, heißt u′ von u
über p erreichbar.
◮
Ein Pfad heißt einfach, wenn alle Knoten verschieden sind.
◮
Ein Teilpfad eines Pfads p = (v0 , v1 , . . . , vk ) ist eine Teilfolge
benachbarter Knoten.
8.1 Mathematische Grundlagen
8-8
Zyklen
◮
Ein Pfad p = (v0 , v1 , . . . , vk ) heißt Zyklus, wenn v0 = vk und
k > 0 ist.
◮
Ein Zyklus ist einfach, wenn seine Knoten paarweise
verschieden sind.
◮
Ein Graph ohne Schlingen wird einfach genannt.
◮
Ein Graph ohne Zyklen wird als azyklisch bezeichnet.
8.1 Mathematische Grundlagen
8-9
Zusammenhang
◮
Ein ungerichteter Graph heißt zusammenhängend, wenn
jedes Knotenpaar durch einen Pfad verbunden ist.
◮
Die Zusammenhangskomponenten eines ungerichteten
Graphen sind die Äquivalenzklassen bezüglich der
Äquivalenzrelation „ist erreichbar von“.
◮
Ein gerichteter Graph heißt stark zusammenhängend, wenn
jeder Knoten von jedem anderen Knoten aus erreichbar ist.
◮
Die starken Zusammenhangskomponenten eines gerichteten
Graphen sind die Äquivalenzklassen bezüglich der
Äquivalenzrelation „sind gegenseitig erreichbar“.
8.1 Mathematische Grundlagen
8-10
Teilgraphen und Isomorphie
◮
Ein Graph G ′ = (V ′ , E ′ ) ist ein Teilgraph von G = (V , E ), falls
V ′ ⊆ V und E ′ ⊆ E gilt.
◮
Ist eine Teilmenge V ′ ⊆ V gegeben, dann ist der durch V ′
induzierte Teilgraph Graph G ′ = (V ′ , E ′ ) von G = (V , E )
durch
E ′ = {(u, v ) ∈ E | u, v ∈ V ′ }.
bestimmt.
◮
Zwei Graphen G = (V , E ) und G ′ = (V ′ , E ′ ) sind isomorph,
wenn es eine bijektive Abbildung f : V → V ′ mit
(u, v ) ∈ E ⇔ (f (u), f (v )) ∈ E ′
gibt.
8.1 Mathematische Grundlagen
8-11
Spezielle Graphen
◮
Ein vollständiger Graph ist ein Graph, in dem jedes
Knotenpaar benachbart ist:
u, v ∈ V ⇒ (u, v ) ∈ E
◮
Ein bipartiter Graph ist ein Graph, in dem die Knotenmenge V
in zwei Teilmengen V1 und V2 zerlegt werden kann, dass alle
Kanten zwischen V1 und V2 verlaufen:
(u, v ) ∈ E ⇒ (u ∈ V1 , v ∈ V2 ) ∨ (u ∈ V2 , v ∈ V1 )
8.1 Mathematische Grundlagen
8-12
Bäume
◮
Ein Wald ist ein azyklischer, ungerichteter Graph.
◮
Ein (freier) Baum ist ein zusammenhängender Wald.
◮
Ein (gerichteter) Baum ist ein freier Baum, in dem einer der
Knoten vor den anderen ausgzeichnet ist. Dieser Knoten
heißt Wurzel.
◮
In einem geordneten Baum sind die Kinder jedes Knotens
geordnet.
Mit diesen Definitionen, können wir die Begriffe Kind, Vater,
Vorfahre, Höhe, Tiefe, binärer Baum, k -närer Baum, . . .
graphentheoretisch interpretieren.
8.1 Mathematische Grundlagen
8-13
Gewichtete Graphen
◮
Ein gewichteter Graph G = (V , E , w ) besteht aus einem
Graphen (V , E ) und einer Gewichtsfunktion
w : E → R,
die jeder Kante e ∈ E eine reelle Zahl w (e ) als Gewicht
zuordnet.
◮
Das Gewicht w (p ) eines Pfads p = (v0 , v1 , . . . , vk ) ist die
Summe der einzelnen Kantengewichte:
w (p ) :=
k −1
X
w ((vi , vi +1 ))
i =0
8.1 Mathematische Grundlagen
8-14
Kürzeste Pfade
◮
Ungewichtete Graphen: Ein Pfad minimaler Länge zwischen
zwei Knoten heißt kürzester Pfad zwischen diesen Knoten.
◮
Gewichtete Graphen: Ein Pfad minimalen Gewichts zwischen
zwei Knoten heißt kürzester Pfad zwischen diesen Knoten.
◮
Die Länge bzw. das Gewicht des kürzesten Pfades zwischen
zwei Knoten ist die Distanz der beiden Knoten.
◮
Kürzeste Pfade müssen nicht existieren (Beispiel: es existiert
ein Zyklus mit negativem Gewicht, der beliebig oft durchlaufen
werden kann).
◮
Kürzeste Pfade sind im Allgemeinen nicht eindeutig bestimmt.
8.1 Mathematische Grundlagen
8-15
Erweiterungen
◮
Ein Multigraph ist ein Graph, der Mehrfachkanten enthalten
kann.
◮
Eine Kante in einem Hypergraphen kann mehr als zwei
Knoten verbinden.
8.1 Mathematische Grundlagen
8-16
Nützliche Funktionen
Bei gerichteten Graphen:
◮
◮
Ausgangskanten: ak : V → P(E ),
ak (u) = {(u, v ) | (u, v ) ∈ E }
Eingangskanten: ek : V → P(E ),
ek (u) = {(v , u) | (v , u) ∈ E }
◮
Ausgangsgrad: ag : V → N0 ,
ag (u) = |ak (u)|
◮
Eingangsgrad: eg : V → N0 ,
eg (u) = |ek (u)|
8.2 Darstellung von Graphen
f
e
g
c
a
b
d
ak (a ) = {(a , g ), (a , b )}
ek (g ) = {(a , g ), (b , g ), (f , g )}
8-17
Nützliche Funktionen
◮
◮
Nachfolgerknoten:
nk : V → P(V ),
nk (u) = {v | (u, v ) ∈ E }
Vorgängerknoten: vk : V → P(V ),
vk (u) = {v | (v , u) ∈ E }
8.2 Darstellung von Graphen
f
e
g
c
a
b
d
nk (a ) = {g , b }
8-18
Möglichkeiten zur Speicherung von Graphen
◮
Kantenlisten
◮
Knotenlisten
◮
Adjazenzmatrizen
◮
Adjazenzlisten
8.2 Darstellung von Graphen
8-19
Kantenlisten
◮
Nummerierung der Knoten von 1 bis
|V | = n
◮
Speicherung: |V |, |E |, Paare (a , b ) mit
(a , b ) ∈ E . Es werden 2 + |E | ∗ 2
Werte unsortiert gespeichert.
◮
Einfügen von Kanten und Knoten:
O (1)
◮
Löschen von Kanten erfordert ein
Durchsuchen der Liste: O (|E |)
◮
Löschen von Knoten erfordert ein
erneutes Nummerieren der Knoten
und ggf. Löschen von Kanten: O (|E |)
8.2 Darstellung von Graphen
6
5
7
3
1
2
4
Kantenliste: 7, 9, 1, 2, 1, 7, 2, 7,
3, 2, 3, 4, 3, 5, 4, 5, 5, 6, 6, 7
8-20
Knotenliste
◮
Nummerierung der Knoten von 1 bis
|V | = n
◮
Speicherung: |V |, |E |, (ag (v ), nk (v ))
mit v ∈ V aufsteigend sortiert. Es
werden 2 + |V | + |E | Werte
gespeichert.
◮
Einfügen von Knoten: O (1)
◮
Einfügen und Löschen von Kanten
erfordert ein Durchsuchen der Liste:
O (|E | + |V |)
◮
Löschen von Knoten erfordert ein
erneutes Nummerieren der Knoten
und ggf. Löschen von Kanten:
O (|E | + |V |)
8.2 Darstellung von Graphen
6
5
7
3
1
2
4
Knotenliste: 7, 9, 2, 2, 7, 1, 7, 3,
2, 4, 5, 1, 5, 1, 6, 1, 7, 0
8-21
Adjazenzmatrizen
Ein Graph G = (V , E ) mit |V | = n wird als quadratische
n × n-Matrix a von booleschen Werten gespeichert. Es gilt
a [i , j ] = true ⇔ (i , j ) ∈ E .
Beispiel für einen gerichteten Graphen:
1
3
2
4


 1 1 0 1 
 0 0 0 1 


 0 0 1 1 


0 0 0 0
Bei ungerichteten Graphen braucht aus Symmetriegründen nur
eine Hälfte der Matrix gespeichert zu werden.
8.2 Darstellung von Graphen
8-22
Adjazenzliste
◮
◮
Nummerierung der Knoten von 1 bis |V |.
Implementierung durch |V | + 1 Listen:
◮
◮
Basisliste: Liste aller Knoten des Graphen.
Pro Knoten: Liste der Nachfolger des Knotens.
6
7
5
1
2
2
7
7
4
3
···
7
1
8.2 Darstellung von Graphen
2
8-23
Vergleich der Implementierungen
Es sei |V | = n, |E | = m.
Speicherbedarf
Kante Einfügen
Kante Löschen
Knoten Einfügen
Knoten Löschen
Kantenliste
Knotenliste
Adjazenzmatrix
Adjazenzliste
O(m)
O (1)
O (m)
O (1)
O (m)
O (n + m)
O (n + m)
O (n + m)
O (1)
O (n + m)
O (n2 )
O (1)
O (1)
O (n2 )
O (n2 )
O (n + m)
O (n)∗
O (n + m)∗
O (1)
O (n + m)
∗)
8.2 Darstellung von Graphen
für die hier gegebene Implementierung
8-24
Übersicht
In diesem Abschnitt wollen wir beispielhaft einige Algorithmen für
ungewichtete Graphen vorstellen.
◮
Systematisches Durchsuchen eines Graphen
◮
◮
Breitensuche (breadth-first search)
Tiefensuche (depth-first search)
◮
Zyklenfreiheit
◮
Topologisches Sortieren
◮
Erreichbarkeit
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
8-25
Breitensuche
Besuch aller Knoten eines Graphen G = (V , E ), die von einem
Startknoten s erreichbar sind.
◮
Es wird von s ausgegangen.
◮
Zuerst werden alle von s über eine Kante erreichbaren
Knoten besucht.
◮
Dann alle über zwei Kanten erreichbaren Knoten.
◮
usw.
2. Iteration
Startknoten
1. Iteration
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
8-26
Breitensuche
◮
Iterative Kontrollstruktur
◮
Schlange Q zur Speicherung der gerade bearbeiteten Knoten
in Reihenfolge der Iterationsschritte
Drei Verzeichnisse (Abbildungen, Dictionaries)
◮ d : V → N0 bildet jeden Knoten auf seine Entfernung vom
◮
◮
◮
Startknoten ab.
p : V → V bildet jeden Knoten auf den Vorgängerknoten ab,
von dem ausgehend er erreicht worden ist. p ergibt nach der
Abarbeitung einen Breitensuchbaum.
c : V → {weiß, schwarz, grau} ordnet jedem Knoten eine
Farbe abhängig von seinem Bearbeitungszustand zu:
◮
◮
◮
weiß: noch unentdeckt,
grau: Entfernung bereits bestimmt,
schwarz: abgearbeitet.
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
8-27
Breitensuche
proc BFS(G,s) begin
foreach u ∈ V \ {s} do
c(u) ← weiß; d(u) ← ∞; p(u) ← nil od;
c(s) ← grau; d(s) ← 0; p(s) ← nil;
Q ← empty;
enter(Q,s);
while! isempty(Q) do
u ← front(Q); leave(Q);
foreach v ∈ nk(u) do
if c(v) = weiß then
c(v) ← grau; d(v) ← d(u)+1;
p(v) ← u; enter(Q,v) fi; od;
c(u) ← schwarz; od;
end
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
8-28
Breitensuche
r
s
v
w
t
u
r
s
x
y
v
w
q: s
t
u
r
s
t
u
x
y
v
w
x
q: r, t, x
y
q: w, r
r
s
t
u
r
s
t
u
r
s
t
u
v
w
x
q: t, x, v
y
v
w
x
q: x, v, u
y
v
w
x
q: v, u, y
y
r
s
t
u
r
s
t
u
r
s
t
u
v
w
x
y
v
w
x
y
v
w
x
y
q: u, y
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
q: y
q: leer
8-29
Breitensuche
Satz: Es sei G = (V , E ) ein gerichteter oder ungerichteter Graph,
auf dem die Prozedur BFS für einen Startknoten s ∈ V ausgeführt
wird.
1. Die Prozedur entdeckt jeden Knoten v ∈ V , der von s aus
erreichbar ist. Bei der Terminierung ist d (v ) gleich der Distanz
von v von s für alle v ∈ V .
2. Die Laufzeit der Breitensuche liegt in O (|V | + |E |), das heißt,
die Laufzeit ist linear in der Größe der Adjazenzliste.
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
8-30
Breitensuche
Der implizit über das Verzeichnis p erzeugte Breitensuchbaum ist
r
s
t
u
v
w
x
y
Die Pfade von jedem Knoten in diesem Baum zum Startknoten
entsprechen kürzesten Pfaden in G .
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
8-31
Tiefensuche
Besuch aller Knoten eines Graphen G = (V , E ).
◮
Es wird von einem Startknoten s ausgegangen.
◮
Es wird rekursiv so weit wie möglich auf einem Pfad
vorangeschritten.
◮
Danach wird zu einer Verzweigung mit einem noch nicht
besuchten Knoten zurückgegangen (Backtracking).
1
a
14
j
13
11
10
i
6
2
b
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
d
12 3
16 15
f
e
9
7
h
c
4
8
g
5
8-32
Tiefensuche
◮
Rekursive Kontrollstruktur
◮
Prozeduren DFS(G) und DFS-visit(u)
◮
Zeitstempel
Vier Verzeichnisse (Abbildungen, Dictionaries)
◮ d : V → N0 Beginn der Bearbeitung eines Knotens
◮ f : V → N0 Ende der Bearbeitung eines Knotens
◮ p : V → V Vorgängerknoten
◮ c : V → {weiß, schwarz, grau} wie oben
◮
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
8-33
Tiefensuche
proc DFS(G) begin
foreach u ∈ V do
c(u) ← weiß; p(u) ← nil od;
zeit ← 0;
foreach u ∈ V do
if c(u) = weiß then
DFS-visit(u) fi; od;
end
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
8-34
Tiefensuche
proc DFS-visit(u): begin
c(u) ← grau;
zeit ← zeit+1;
d(u) ← zeit;
foreach v ∈ nk(u) do
if c(v) = weiß then
p(v) ← u;
DFS-visit(v) fi; od;
c(u) ← schwarz;
zeit ← zeit+1;
f(u) ← zeit;
end
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
8-35
Tiefensuche
1/
u
/
v
/
w
1/
u
2/
v
/
w
1/
u
2/
v
/
w
1/
u
2/
v
/
w
x
/
y
/
z
/
x
/
y
/
z
/
x
/
y
3/
z
/
x
4/
y
3/
z
/
1/
u
2/
v
/
w
1/
u
2/
v
/
w
1/
u
2/
v
/
w
1/
u
2/7
v
/
w
y
3/6
z
/
B
x
4/
B
y
3/
z
/
x
4/5
B
y
3/
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
z
/
x
4/5
B
y
3/6
z
/
x
4/5
8-36
Tiefensuche
1/
u
/
w
2/7
v
FB
1/8
u
/
w
2/7
v
1/8
u
FB
9/
w
2/7
v
FB
1/8
u
9/
w
2/7
v
FB
C
x
4/5
y
3/6
z
/
x
4/5
y
3/6
z
/
x
4/5
y
3/6
z
/
x
4/5
y
3/6
z
/
1/8
u
2/7
v
9/
w
1/8
u
2/7
v
9/
w
1/8
u
2/7
v
9/
w
1/8
u
2/7
v
9/12
w
FB
x
4/5
FB
C
y
3/6
z
10/
x
4/5
FB
C
y
3/6
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
z
10/
B
x
4/5
C
y
3/6
z B
10/11
FB
x
4/5
C
y
3/6
z B
10/11
8-37
Tiefensuche
Der implizit über das Verzeichnis p erzeugte Tiefensuchwald ist
1/8
u
2/7
v
FB
x
4/5
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
9/12
w
C
y
3/6
z B
10/11
8-38
Tiefensuche
Klassifikation der Kanten:
1. Baumkanten sind Kanten im Tiefensuchwald.
2. Rückwärtskanten B sind Kanten, die einen Knoten mit einem
Vorfahren im Tiefensuchwald verbinden.
3. Vorwärtskanten F sind diejenigen Nichtbaumkanten, die einen
Knoten mit einem Nachfahren im Tiefensuchwald verbinden.
4. Querkanten C sind alle übrigen Kanten. Sie können zwischen
verschiedenen Tiefensuchbäume verlaufen.
Bei einer Tiefensuche auf einem ungerichteten Graphen ist jede
Kante eine Baumkante oder eine Rückwärtskante.
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
8-39
Zyklenfreiheit
Mithilfe der Tiefensuche können Zyklen in gerichteten Graphen
ermittelt werden. Es gilt:
Ein gerichteter Graph G ist genau dann azyklisch, wenn der
Tiefensuchalgorithmus auf G keine Rückwärtskanten liefert.
Beweis: s. Cormen et al., Seite 554.
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
8-40
Topologisches Sortieren
◮
Gegeben sei ein gerichteter azyklischer Graph G = (V , E ).
Solche Graphen werden als DAG (directed acyclic graph)
bezeichnet.
◮
Eine topologische Sortierung von G ist eine lineare
Anordnung seiner Knoten mit der Eigenschaft, dass u vor v
liegt, wenn es einen Pfad von u nach v gibt.
◮
Gesucht ist ein Algorithmus, der zu einem DAG G = (V , E )
eine topologische Sortierung seiner Knotenmenge V
berechnet.
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
8-41
Topologisches Sortieren
Beispiel: Gesucht ist die Reihenfolge beim Ankleiden. Nach
Festlegung der Reihenfolge einzelner Kleidungsstücke entsteht
folgender Graph:
Socken
Unterhose
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
Schuhe
Hose
Hemd
Gürtel
Fliege
Uhr
Jacke
8-42
Topologisches Sortieren
Mit Tiefensuche kann für jeden Knoten die Endzeit seiner
Bearbeitung bestimmt werden. Sie ergibt eine topologische
Sortierung.
Ist die Bearbeitung eines
Knotens abgeschlossen, so
wird er am Kopf der zu Beginn
leeren Ergebnisliste eingefügt.
Die Ergebnisliste gibt die
Sortierung an.
Reihenfolge: Socken (18),
Unterhose (16), Hose (15),
Schuhe (14), Uhr (10), Hemd
(8), Gürtel (7), Fliege (5),
Jacke (4)
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
Socken
17/18
Unterhose
11/16
Schuhe
13/14
Hose
12/15
Hemd
1/8
Gürtel
6/7
Fliege
2/5
Uhr
9/10
Jacke
3/4
8-43
Floyd-Warshall-Algorithmus
Es soll die reflexive, transitive Hülle einer Relation bestimmt
werden. Dieses Problem entspricht dem Erreichbarkeitsproblem in
einem Graphen.


 0 1 0 0 
 0 0 0 1 


 0 0 0 1 


0 0 0 0
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
1
2
3
4


 1 1 0 1 
 0 1 0 1 


 0 0 1 1 


0 0 0 1
8-44
Floyd-Warshall-Algorithmus
Es sei V = {1, . . . , n}. Die Relation E ⊆ V × V liege als
Adjazenzmatrix r vor. Für 1 ≤ i , j ≤ n sei



true
r [i , j ] = 

false
falls
(i , j ) ∈ E
sonst
func FloyWars(r: bool [n,n]): bool [n,n] begin
var i,j,k: int;
for i ← 1 to n do r[i,i] ← true; od;
for k ← 1 to n do
for i ← 1 to n do
for j ← 1 to n do
r[i,j] ← r[i,j] ∨
(r[i,k] ∧ r[k,j]);
od; od; od;
return r;
end
8.3 Ausgewählte Algorithmen für ungewichtete Graphen
8-45
Übersicht
In diesem Abschnitt wollen wir beispielhaft einige Algorithmen für
gewichtete Graphen vorstellen.
◮
Minimale Spannbäume
◮
◮
◮
Algorithmus von Kruskal
Algorithmus von Prim
Kürzeste Pfade von einem Startknoten
◮
◮
Algorithmus von Dijkstra
Bellmann-Ford-Algorithmus
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-46
Minimale Spannbäume
◮
◮
Gegeben sei ein gewichteter Graph G = (V , E , w ).
Gesucht ist eine azyklische Teilmenge T ⊆ E , die alle Knoten
verbindet und deren Gesamtgewicht
w (T ) =
X
w (e )
e ∈T
◮
◮
minimal ist.
Eine Kantenmenge, die azyklisch ist und alle Knoten
verbindet, ist ein Baum, der Spannbaum genannt wird.
Es ist also ein minimaler Spannbaum gesucht.
4
3
3
3
2 6
8
6
4
◮
5
5
7
6
2
Dieser Baum ist im Allgemeinen nicht eindeutig bestimmt.
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-47
Basisalgorithmus
◮
Der Algorithmus verwaltet eine Kantenmenge A , die den
minimalen Spannbaum Kante für Kante aufbaut.
◮
A ist stets Teilmenge eines minimalen Spannbaums.
◮
Eine Kante e ∈ E , die zu A hinzugefügt werden kann, ohne
die Eigenschaft zu verletzen, dass A Teilmenge eines
minimalen Spannbaums ist, heißt sichere Kante für A .
proc MST-Basis(G) begin
A ← ∅;
while A bildet keinen Spannbaum do
bestimme eine Kante e ∈ E ,
die sicher für A ist;
A ← A ∪ {e};
od;
return A;
end
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-48
Basisalgorithmus
Satz: Es sei G = (V , E ) ein zusammenhängender, gewichteter
Graph. A sei eine Teilmenge eines minimalen Spannbaums und
C = (VC , EC ) eine Zusammenhangskomponente aus dem Wald
GA = (V , A ). Dann gilt: Falls e ∈ E eine Kante mit minimalen
Gewicht ist, die C mit einer anderen Komponente von GA
verbindet, dann ist e sicher für A .
Beweis: s. Cormen, S. 569 f.
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-49
Operationen für disjunkte Mengen
◮
MakeSet(x)
erzeugt die einelementige Menge {x }. x darf nicht bereits in
einer anderen Menge enthalten sein.
◮
Union(x,y)
bildet die Vereinigungsmenge x ∪ y . Es wird x ∩ y = ∅
vorausgesetzt.
◮
FindSet(x)
liefert einen Zeiger auf den Repäsentanten der eindeutig
bestimmten Menge, die x enthält.
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-50
Algorithmus von Kruskal
◮
Selektiere fortwährend eine verbleibende Kante mit
geringstem Gewicht, die keinen Zyklus erzeugt, bis alle
Knoten verbunden sind (Kruskal, 1956).
◮
Eine eindeutige Lösung ist immer dann vorhanden, wenn alle
Gewichte verschieden sind.
4
3
8
3
2 6
6
4
3
5
5
7
6
2
Nach Wahl der Kanten 2, 2, 3 und 3 darf die verbleibende 3 nicht
gewählt werden, da sonst ein Zyklus entstünde.
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-51
Algorithmus von Kruskal
proc MST-Kruskal(G) begin
A ← ∅;
foreach v ∈ V do MakeSet(v) od;
sortiere die Kanten aufsteigend nach
ihrem Gewicht;
foreach (u,v) ∈ E do
if FindSet(u) , FindSet(v) then
A ← A ∪ {(u,v)}
UnionSet(FindSet(u), FindSet(v));
fi;
od;
return A;
end
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-52
Algorithmus von Kruskal
◮
A ist zu jedem Zeitpunkt ein Wald, dessen Komponenten
nach und nach zu einem minimalen Spannbaum verbunden
werden.
◮
Die Laufzeit hängt von der Implementierung der disjunkten
Mengen ab.
◮
Bei einer geeigneten Realisierung der disjunkten Mengen
liegt die Laufzeit des Algorithmus von Kruskal in O (|E | log |V |).
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-53
Algorithmus von Prim
◮
Beim Algorithmus von Prim bildet die Kantenmenge A stets
einen Baum.
◮
Der Baum startet bei einem beliebigen Wurzelknoten und
wächst, bis er V aufspannt.
◮
In jedem Schritt wird eine Kante hinzugefügt, die A mit einem
isolierten Knoten von GA = (V , A ) verbindet und die
bezüglich dieser Eigenschaft minimal ist.
◮
Der Algorithmus verwendet zur Verwaltung der Knoten eine
Min-Prioritätswarteschlange Q , die auf einem Attribut
schlüssel basiert. Für jeden Knoten v ist schlüssel(v) das
kleinste Gewicht aller Kanten, die v mit einem Knoten des
Baums verbinden.
◮
p (v ) bezeichnet den Vater von v .
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-54
Algorithmus von Prim
proc MST-Prim(G,r) begin
foreach u ∈ V do
schlüssel(u) ← ∞; p(u) ← nil; od;
schlüssel(r) ← 0;
Q ← V;
while Q , ∅ do
u ← ExtractMin(Q);
foreach v ∈ nk(u) do
if v ∈ Q und w(u,v) < schlüssel(v)
then p(v) ← u;
schlüssel(v) ← w(u,v); fi;
od;
od;
end
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-55
Algorithmus von Prim
◮
Die Laufzeit des Algorithmus von Prim hängt von der
Implementierung der Min-Prioritätswarteschlange Q ab.
◮
Die Anweisung schlüssel(v) ← w(u,v) ist beispielsweise
eine Decrease-Operation.
◮
Wenn Q als binärer Min-Heap realisiert wird, liegt die Laufzeit
des Algorithmus von Prim in O (|E | log |V |). Dies entspricht der
Laufzeit des Algorithmus von Kruskal.
◮
Durch Verwendung von so genannten Fibonacci-Heaps kann
die Laufzeit des Algorithmus von Prim auf O (|E | + |V | log |V |)
verbessert werden.
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-56
Problem der kürzesten Pfade bei einem Startknoten
◮
Gegeben ist ein gewichteter Graph G = (V , E , w ) und ein
Startknoten s ∈ V .
◮
Gesucht ist für jeden Knoten v ∈ V ein Pfad p = (v0 , . . . , vk )
von s = v0 nach v = vk , dessen Gewicht
w (p ) =
k
X
w (vi −1 , vi )
i =1
minimal wird. Falls kein Pfad von s nach v existiert, sei das
Gewicht ∞.
◮
Die Gewichte können im Allgemeinen negativ sein.
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-57
Problem der kürzesten Pfade bei einem Startknoten
Beispiel: Bestimme den kürzesten Weg von Frankfurt nach Celle
Augsburg
3
2
9
9
4
Frankfurt
Braunschweig
9
1
8
Erfurt
2
3
2
8
Celle
9
3
6
Darmstadt
Der kürzester Weg ist (Frankfurt, Augsburg, Braunschweig, Celle).
Er hat das Gewicht 6.
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-58
Bellmann-Ford-Algorithmus
◮
Der Algorithmus verwendet so genannte Relaxationen und
bestimmt so immer kleiner werdende Schätzungen d (v ) für
das Gewicht eines kürzesten Pfads vom Startknoten s aus zu
allen Knoten v ∈ V , bis er das tatsächliche Gewicht erreicht
hat.
◮
Der Algorithmus gibt genau dann wahr zurück, wenn der
Graph keine Zyklen mit negativem Gewicht enthält, die von s
aus erreichbar sind.
◮
p (v ) ist wie bisher der Vaterknoten von v .
◮
Der Algorithmus führt |V | − 1 Durchläufe über die Kanten des
Graphen aus.
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-59
Bellmann-Ford-Algorithmus
Initialisierung:
proc Init(G,s) begin
foreach v ∈ V do
d(v) ← ∞;
p(v) ← nil; od;
d(s) ← 0;
end
Relaxation:
proc Relax(u,v,w) begin
if d(v) > d(u) + w(u,v)
then d(v) ← d(u) + w(u,v);
p(v) ← u; fi;
end
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-60
Bellmann-Ford-Algorithmus
proc Bellmann-Ford(G, s) boolean begin
Init(G,s);
for i ← 1 to |V| - 1 do
foreach (u,v) ∈ E do
Relax(u,v,w); od; od;
foreach (u,v) ∈ E do
if d(v) > d(u) + w(u,v)
then return false; fi; od;
return true;
end
Die Laufzeit des Bellmann-Ford-Algorithmus liegt in O (|E | · |V |).
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-61
Algorithmus von Dijkstra
◮
Der Algorithmus von Dijkstra löst das Problem der kürzesten
Pfade bei einem Startknoten, falls alle Gewichte nichtnegativ
sind.
◮
Wir setzen daher w (e ) ≥ 0 für alle e ∈ E voraus.
◮
Die Laufzeit des Dijkstra-Algorithmus ist bei guter
Implementierung besser als die des
Bellmann-Ford-Algorithmus.
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-62
Algorithmus von Dijkstra
◮
Der Dijkstra-Algorithmus verwaltet eine Menge S von Knoten,
deren endgültige Gewichte der kürzesten Pfade vom
Startknoten aus bereits bestimmt wurden.
◮
Der Algorithmus wählt in jedem Schritt denjenigen Knoten
u ∈ V \ S mit der kleinsten Schätzung des kürzesten Pfads
aus, fügt u zu S hinzu und relaxiert alle aus u austretenden
Kanten
◮
In der Implementierung wird eine Min-Prioritätswarteschlange
Q für Knoten verwendet. Dabei dienen die d -Werte als
Schlüssel.
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-63
Algorithmus von Dijkstra
proc Dijkstra(G, s) begin
Init(G,s);
S ← ∅;
Q ← V;
while Q , ∅ do
u ← ExtractMin(Q);
S ← S ∪ {u};
foreach v ∈ nk(u)
Relax(u,v,w); od; od;
end
Die Laufzeit des Dijkstra-Algorithmus hängt von der
Implementierung der Min-Prioritätswarteschlange Q ab. Bei guter
Implementierung von Q liegt die Laufzeit des Dijkstra-Algorithmus
in O (|E | + |V | · log |V |).
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-64
Algorithmus von Dijkstra
t
∞
x
∞
1
t
10
3
2
5
9
6
4
s
0
3
5
y
Q = [s,t,x,y,z]
t
8
2
6
4
s
0
5
5
y
3
2
5
6
4
5
y
2
7
z
Q = [t,x]
8.4 Ausgewählte Algorithmen für gewichtete Graphen
x
9
1
10
3
2
5
7
7
z
2
t
8
10
s
0
4
Q = [z,t,x]
x
9
1
6
7
∞
z
2
t
8
10
9
2 9
3
Q = [y,t,x,z]
x
13
1
9
7
∞
z
2
x
14
1
10
5
7
∞
y
s
0
t
8
10
10
s
0
x
∞
1
9
6
4
2
Q = [x]
3
2
5
7
5
y
s
0
7
z
9
6
4
7
5
y
2
7
z
Q = []
8-65
Ausblick
Die Graphentheorie ist ein umfangreiches Gebiet, in dem viele
weitere Fragestellungen untersucht werden. Wir stellen drei davon
kurz vor:
◮
Problem des Handlungsreisenden,
◮
planare Graphen,
◮
Färbungen von Graphen.
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-66
Problem des Handlungsreisenden
◮
◮
Gegeben seien n durch Straßen verbundene Städte mit
Reisekosten c (i , j ) zwischen je zwei Städten i und j ,
1 ≤ i , j ≤ n.
Gesucht ist die billigste Rundreise, die jede Stadt genau
einmal besucht (Traveling Salesman Problem, TSP).
Augsburg
3
2
9
9
4
Frankfurt
Braunschweig
9
1
8
Erfurt
2
3
2
8
Celle
9
3
6
Darmstadt
Die billigste Rundreise kostet 13 Einheiten.
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-67
Planare Graphen
◮
Gegeben sei ein beliebiger Graph G . Lässt sich G planar
zeichnen, das heißt, ohne sich schneidende Kanten?
◮
Im Beispiel unten ist dies möglich, im Allgemeinen jedoch
nicht.
◮
Anwendung: Chip- oder Leiterplattendesign. Leiterbahnen
sollen möglichst kreuzungsfrei gestaltet werden.
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-68
Färbungen von Graphen
◮
◮
◮
Gegeben sei ein Graph G . Die Knoten von G sollen derart
gefärbt werden, dass benachbarte Knoten verschiedene
Farben besitzen. Wie viele Farben werden benötigt?
Im Beispiel unten reichen bereits drei Farben. Für planare
Graphen werden im Allgemeinen vier Farben benötigt. Dieses
Ergebnis wurde 1976 von K. Appel und W. Haken gezeigt
(Vierfarbenproblem). Der Beweis war sehr umfangreich und
computergestützt.
Anwendungen: Einfärben von Landkarten (Knoten , Land,
Kante , Grenze), Vergabe überschneidungsfreier
Klausurtermine (Knoten , Fach, Kante , beide Fächer
werden vom gleichen Studenten gehört, Farbe , Termin)
8.4 Ausgewählte Algorithmen für gewichtete Graphen
8-69
Herunterladen