Datenstrukturen und Algorithmen

Werbung
Elementare Graphenalgorithmen I
Elementare Graphenalgorithmen I
Übersicht
Datenstrukturen und Algorithmen
Vorlesung 14: Elementare Graphenalgorithmen I
1
Graphen
Terminologie
Repräsentation von Graphen
2
Graphendurchlauf
Breitensuche
Tiefensuche
Finden von Zusammenhangskomponenten
Joost-Pieter Katoen
Lehrstuhl für Informatik 2
Software Modeling and Verification Group
http://www-i2.rwth-aachen.de/i2/dsal10/
15. Juni 2010
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Elementare Graphenalgorithmen I
Graphen
1/36
Übersicht
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Elementare Graphenalgorithmen I
Graphen
2/36
Die Bedeutung von Graphen
Graphen werden in vielen (Informatik-)Anwendungen verwendet:
1
2
Graphen
Terminologie
Repräsentation von Graphen
Beispiele
Graphendurchlauf
Breitensuche
Tiefensuche
Finden von Zusammenhangskomponenten
I
(Computer-)Netzwerke
I
Darstellung von topologischen Informationen (Karten, . . . )
I
Darstellung von elektronischen Schaltungen
I
Vorranggraphen (precedence graph), Ablaufpläne, . . .
I
Semantische Netze (z. B. Entity-Relationship-Diagramme)
Wir werden uns auf fundamentale Graphalgorithmen konzentrieren.
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
3/36
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
4/36
Elementare Graphenalgorithmen I
Graphen
Elementare Graphenalgorithmen I
Was ist ein gerichteter Graph? (I)
Graphen
Was ist ein gerichteter Graph? (I)
Beispiel
Gerichteter Graph
I
V = { A, . . . , F }
Ein gerichteter Graph (auch: Digraph) G ist ein Paar (V , E ) mit
I
E = { (A, B), (A, D), (B, E ), (C , E ), (C , F ), (D, B), (E , D), (F , F ) }
I
einer Menge Knoten (vertices) V und
I
einer Menge (geordneter) Paare von Knoten E ⊆ V × V , die
(gerichtete) Kanten (edges) genannt werden.
I
A
C
B
Kante
Knoten
Falls E eine Menge ungeordneter Paare ist, heißt G ungerichtet.
D
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Elementare Graphenalgorithmen I
Graphen
5/36
F
E
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Elementare Graphenalgorithmen I
Graphen
6/36
Terminologie bei Graphen (I)
Terminologie bei Graphen (II)
Teilgraph
Vollständiger Graph
Ein Teilgraph (subgraph) eines Graphen G = (V , E ) ist ein Graph
G 0 = (V 0 , E 0 ) mit:
Der Graph G ist vollständig, wenn jedes Paar von Knoten mit einer Kante
verbunden ist.
I
V 0 ⊆ V und E 0 ⊆ E .
I
Außerdem ist E 0 ⊆ V 0 × V 0 wegen der Grapheigenschaft von G 0 .
I
Ist
V0
⊂ V und
E0
⊂ E , so heißt
G0
Adjazent
Knoten w ist adjazent zu v , wenn (v , w ) ∈ E .
echter (proper) Teilgraph.
Symmetrischer Graph
Transponieren
Der Graph G heißt symmetrisch, wenn aus (v , w ) ∈ E folgt (w , v ) ∈ E .
Transponiert man G (transpose graph), so erhält man G T = (V , E 0 ) mit
(v , w ) ∈ E 0 gdw. (w , v ) ∈ E .
I
Zu jedem ungerichteten Graphen gibt es korrespondierenden
symmetrischen Digraphen.
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
I
7/36
In G 0 ist die Richtung der Kanten von G gerade umgedreht.
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
8/36
Elementare Graphenalgorithmen I
Graphen
Elementare Graphenalgorithmen I
Terminologie bei Graphen (III)
Graphen
Pfade und Zyklen (I)
Weg, Pfad
A
C
B
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 vi 6= vj für i 6= j verschieden sind, heißt Pfad.
D
F
E
I
Länge eines Pfades(Weges) ist die Anzahl der durchlaufenen Kanten.
Teilgraph
Erreichbarkeit
A
B
Knoten w heißt erreichbar von v , wenn es einen Pfad von v nach w gibt.
Zyklus
D
E
Ein Zyklus ist ein nicht-leerer Weg bei dem der Startknoten auch
Endknoten ist.
Vollständiger (und symmetrischer) Digraph
auf vier Knoten
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Elementare Graphenalgorithmen I
Graphen
9/36
Pfade und Zyklen (II)
A
B
I
Ein Zyklus der Form vv heißt Schleife (loop, self-cycle).
I
Ein Graph ist azyklisch, wenn er keine Zyklen hat.
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Elementare Graphenalgorithmen I
Graphen
10/36
Zusammenhängende Graphen (I)
C
Beim ungerichteten Graphen G:
Zusammenhang
Schleife
D
E
I
G heißt zusammenhängend, wenn jeder Knoten von jedem anderen
Knoten aus erreichbar ist.
I
Eine Zusammenhangskomponente (connected component) von G ist
ein maximaler zusammenhängender Teilgraph von G.
I
In einer Ansammlung von Graphen heißt ein Graph maximal, wenn er
von keinem anderen dieser Graphen ein echter Teilgraph ist.
F
Zyklus
A B E D B und C F F wären hier Beispiele für Wege.
E D B und C F sind Pfade.
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
11/36
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
12/36
Elementare Graphenalgorithmen I
Graphen
Elementare Graphenalgorithmen I
Zusammenhängende Graphen (II)
Graphen
Ungerichtete, zusammenhängende Graphen
Beim gerichteten Graphen G:
C
B
A
Zusammenhang
I
I
G heißt stark zusammenhängend (strongly connected), wenn jeder
Knoten von jedem anderen aus erreichbar ist.
I
G heißt schwach zusammenhängend, wenn der zugehörige
ungerichtete Graph (wenn man alle Kanten ungerichtet macht)
zusammenhängend ist.
I
Eine starke Zusammenhangskomponente von G ist ein maximaler
stark zusammenhängender Teilgraph von G.
I
Ein nicht-verbundener Graph kann eindeutig in verschiedene
Zusammenhangskomponenten aufgeteilt werden.
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Elementare Graphenalgorithmen I
Graphen
F
J
G
D
E
Ein ungerichteter Graph; Was sind die Zusammenhangskomponenten?
13/36
Ungerichtete, zusammenhängende Graphen
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Elementare Graphenalgorithmen I
Graphen
14/36
Starke Zusammenhangskomponenten
C
B
A
H
I
F
J
G
D
Zusammenhangskomponenten
H
E
Ein nicht-zusammenhängender Digraph, aufgeteilt in seine maximalen
zusammenhängenden Teilgraphen.
Die Zusammenhangskomponenten.
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
15/36
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
16/36
Elementare Graphenalgorithmen I
Graphen
Elementare Graphenalgorithmen I
Repräsentation von Graphen – Adjazenzmatrix
Repräsentation von Graphen – Adjazenzliste
Adjazenzliste
Sei G = (V , E ) mit |V | = n, |E | = m und V = { v1 , . . . , vn }.
Adjazenzmatrix
Die Adjazenzmatrix-Darstellung eines Graphen ist durch eine n × n Matrix
A gegeben, wobei A(i, j) = 1, wenn (vi , vj ) ∈ E , sonst 0.
I
Graphen
Wenn G ungerichtet ist, ergibt sich symmetrisches A (d. h. A = AT ).
Dann muss nur die Hälfte 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.
I
Der i-te Arrayeintrag enthält alle Kanten von G, die von vi
„ausgehen“.
I
Ist G ungerichtet, dann werden Kanten doppelt gespeichert.
I
Kanten, die in G nicht vorkommen, benötigen keinen Speicherplatz.
⇒ Platzbedarf: Θ(n + m).
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Elementare Graphenalgorithmen I
Graphen
17/36
Darstellung eines ungerichteten Graphen
A
A
B
C
D
E
B
C
E
D
B
A
D
C
D
E
E
B
E
B
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Elementare Graphenalgorithmen I
Graphen
Darstellung eines gerichteten Graphen
A
D





C
B
A
D
F
E
0
1
0
0
1
1
0
1
1
1
0
1
0
1
0
0
1
1
0
1
1
1
0
1
0














Datenstrukturen und Algorithmen
B
E
F
B
D
F
D
E
Adjazenzliste
Adjazenzmatrix
Joost-Pieter Katoen
A
B
C
D
E
F
C
B
Adjazenzliste

18/36
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
19/36
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
20/36
Elementare Graphenalgorithmen I
Graphendurchlauf
Elementare Graphenalgorithmen I
Übersicht
Graphendurchlauf
Graphendurchlauf (I)
Viele Algorithmen untersuchen jeden Knoten (und jede Kante).
1
2
Graphen
Terminologie
Repräsentation von Graphen
Es gibt verschiedene Graphendurchlaufstrategien (traversal strategies), die
jeden Knoten (oder jede Kante) genau einmal besuchen:
Graphendurchlauf
Breitensuche
Tiefensuche
Finden von Zusammenhangskomponenten
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Elementare Graphenalgorithmen I
Graphendurchlauf
21/36
Graphendurchlauf (II)
I
Tiefensuche
I
Breitensuche
I
Es handelt sich um Verallgemeinerungen von Strategien zur
Baumtraversierung.
I
Nun müssen wir uns aber alle bereits gefundenen Knoten merken.
I
Algorithmen auf dieser Basis sind in O(|V | + |E |).
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Elementare Graphenalgorithmen I
Graphendurchlauf
22/36
Breitensuche
Breitensuche (Breadth-First Search, BFS)
Am Anfang seien alle Knoten als „nicht-gefunden“ (WHITE) markiert.
Die zugrundeliegende Strategie ist:
Beispiele
I
Finden von (starken) Zusammenhangskomponenten,
I
Topologische Sortierung,
I
Kritische-Pfad-Analyse,
I
Finden von 2-Zusammenhangskomponenten (biconnected
components),
I
I
I
I
I
. . . und viele weitere . . .
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Markiere den aktuellen Knoten v als „gefunden“ (GRAY).
Für jede Kante (v , w ) im Graph G mit „nicht-gefundenem“
Nachfolger w :
23/36
Suche „gleichzeitig“ von allen solchen w aus weiter.
Kein Backtracking.
I
Markiere Knoten v als „abgeschlossen“ (BLACK).
I
Man erhält die Menge aller Knoten, die vom Startknoten aus
erreichbar sind.
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
24/36
Elementare Graphenalgorithmen I
Graphendurchlauf
Elementare Graphenalgorithmen I
Breitensuche – Beispiel
Breitensuche – Implementierung
1
A
2
D
A
D
3
4
B
B
G
G
5
6
7
F
C
E
F
Beginn der Breitensuche
C
E
8
9
Erforsche alle folgenden nicht-gefundenen Knoten
10
A
A
D
D
11
12
B
B
G
13
G
14
15
F
C
F
E
C
16
E
17
Erforsche alle folgenden nicht-gefundenen Knoten
Fertig!
18
19
20
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Elementare Graphenalgorithmen I
Graphendurchlauf
25/36
Eigenschaften der Breitensuche
I
I
void bfsSearch(List adjList[n], int n, int start) {
int color[n];
Queue wait; // zu verarbeitende Knoten
for (int i = 0; i < n; i++) {
color[i] = WHITE; // noch nicht gefunden
}
color[start] = GRAY; // start ist noch zu verarbeiten
wait.enqueue(start);
while (!wait.isEmpty()) {
// nächster noch unverarbeiteter Knoten
int v = wait.dequeue();
foreach (w in adjList[v]) {
if (color[w] == WHITE) { // neuer ("ungefundener") Knoten
color[w] = GRAY; // w ist noch zu verarbeiten
wait.enqueue(w);
}
}
color[v] = BLACK; // v ist abgeschlossen
}
}
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Elementare Graphenalgorithmen I
Graphendurchlauf
Tiefensuche (Depth-First Search, DFS)
Am Anfang seien alle Knoten als „nicht-gefunden“ (WHITE) markiert.
Die zugrundeliegende Strategie ist:
Nachdem alle Knoten mit Abstand d verarbeitet wurden, werden die
mit d + 1 angegangen.
Die Suche terminiert, wenn in Abstand d keine Knoten auftreten.
I
I
I
Die Tiefe des Knotens v im Breitensuchbaum ist seine kürzeste
Kantendistanz zum Startknoten.
I
Die zu verarbeitenden Knoten werden als FIFO-Queue (first-in
first-out) organisiert.
I
Es gibt eine einzige „Verarbeitungsmöglichkeit“ für v , nämlich, wenn
es aus der Queue entnommen wird.
Markiere den aktuellen Knoten v als „gefunden“ (GRAY).
Für jede Kante (v , w ) im Graph G mit „nicht-gefundenem“
Nachfolger w :
I
I
I
I
Theorem (Komplexität der Breitensuche)
Die Zeitkomplexität ist Θ(|V | + |E |), der Platzbedarf Θ(|V |).
Datenstrukturen und Algorithmen
27/36
Suche rekursiv von w aus, d. h.:
Erforsche Kante (v , w ), besuche w , forsche von dort aus, bis es nicht
mehr weiter geht.
Dann backtracke von w nach v .
Für jede Kante (v , w ) in G mit gefundenem Nachfolger w :
I
Joost-Pieter Katoen
26/36
Tiefensuche
Knoten werden in der Reihenfolge mit zunehmenden Abstand vom
Startknoten aus besucht.
I
Graphendurchlauf
„Überprüfe“ die Kante, ohne aber w zu besuchen.
I
Markiere Knoten v als „abgeschlossen“ (BLACK).
I
Man erhält wieder die Menge aller Knoten, die vom Startknoten aus
erreichbar sind.
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
28/36
Elementare Graphenalgorithmen I
Graphendurchlauf
Elementare Graphenalgorithmen I
Tiefensuche – Beispiel (I)
A
Tiefensuche – Beispiel (II)
D
B
F
A
B
E
F
Beginn der Tiefensuche
A
F
A
F
B
E
F
A
E
F
Sackgasse!
Backtracke und erforsche den nächsten Knoten
Erforsche einen Knoten
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Elementare Graphenalgorithmen I
Graphendurchlauf
29/36
F
C wurde bereits gefunden
Backtracke und erforsche den nächsten Knoten
A
C
3
G
4
E
7
Erforsche den nächsten Knoten
8
9
A
D
B
G
12
G
13
14
F
C
E
F
Beide nächsten Knoten wurden bereits gefunden
Joost-Pieter Katoen
C
G
E
B ist eine Sackgasse
Backtracke und erforsche den nächsten Knoten
30/36
void dfsRec(List adjList[n], int n, int start, int &color[n]) {
color[start] = GRAY;
foreach (next in adjList[start]) {
if (color[next] == WHITE) {
dfsSRec(adjList, n, next, color);
}
}
color[start] = BLACK;
}
D
11
B
F
Graphendurchlauf
1
D
B
G
E
B
G
E
D
Elementare Graphenalgorithmen I
6
C
A
Datenstrukturen und Algorithmen
5
F
C
E
C
Nächster Zustand wurde bereits gefunden
Backtracke und erforsche den nächsten Knoten
Joost-Pieter Katoen
2
B
D
G
Tiefensuche – Implementierung
A
D
F
D ist eine Sackgasse
Backtracke und erforsche den nächsten Knoten
Tiefensuche – Beispiel (III)
A
E
B
G
C
C
D
B
G
Nächster Zustand wurde bereits gefunden
Backtracke und erforsche den nächsten Knoten
D
G
C
E
C
A
D
B
G
Erforsche einen Knoten
D
B
A
D
G
C
Graphendurchlauf
C
15
E
16
Fertig!
Datenstrukturen und Algorithmen
17
31/36
void dfsSearch(List adjList[n], int n, int start) {
int color[n];
for (int i = 0; i < n; i++) { // Initialisierung
color[i] = WHITE;
}
dfsRec(adjList, n, start, color);
}
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
32/36
Elementare Graphenalgorithmen I
Graphendurchlauf
Elementare Graphenalgorithmen I
Eigenschaften der Tiefensuche
Graphendurchlauf
Finden von Zusammenhangskomponenten (I)
Problem
I
Erforsche einen Pfad so weit wie möglich, bevor man backtrackt.
I
Das entspricht der Reihenfolge der rekursiven Aufrufe.
I
Die zu verarbeitenden Knoten werden in LIFO-Reihenfolge geprüft.
Es gibt zwei „Verarbeitungsmöglichkeiten“ für einen Knoten:
I
Finde die Zusammenhangskomponenten des ungerichteten Graphen G.
Lösung
I
1. Wenn der Knoten entdeckt wird.
2. Wenn der Knoten als „abgearbeitet“ markiert wird (und alle seine
Nachfolger entdeckt werden).
I
I
⇒ Diese letztgenannte Möglichkeit macht Tiefensuche beliebt.
I
Theorem (Komplexität der Tiefensuche)
I
Zeitkomplexität: Θ(|V | + |E |), Platzkomplexität: Θ(|V |).
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Elementare Graphenalgorithmen I
Graphendurchlauf
33/36
Finden von Zusammenhangskomponenten (II)
1
2
3
4
5
6
7
8
9
10
11
12
Datenstrukturen und Algorithmen
Beginne bei einem beliebigen Knoten.
Finde alle anderen Knoten (und Kanten) in der selben Komponente mit
DFS.
Wenn es weitere Knoten gibt, wähle einen und wiederhole das
Verfahren.
I
Man erhält einen Tiefensuchwald.
I
Die Zeitkomplexität ist Θ(|V | + |E |).
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
Elementare Graphenalgorithmen I
Graphendurchlauf
34/36
Finden von Zusammenhangskomponenten (III)
// Ausgabe in cc: cc[v] = Komponente von Knoten v
void connComponents(List adjLst[n], int n, int &cc[n]) {
int color[n], ccNum = 0;
for (int v = 0; v < n; v++) { // Initialisierung
color[v] = WHITE;
}
for (int v = 0; v < n; v++) {
if (color[v] == WHITE) { // weitere Komponente
dfsSearch(adjLst, n, v, ccNum++, cc);
}
}
}
Joost-Pieter Katoen
Konstruiere den zugehörigen symmetrischen Digraph (mit 2 · |E |
Kanten).
Verwende Tiefensuche:
1
2
3
4
5
6
7
8
9
10
11
35/36
void dfsSearch(List adjLst[n], int n, int start, int &color[n],
int ccNum, int &cc[n]) {
color[start] = GRAY;
cc[start] = ccNum; // speichere Nummer der Komponente von v
foreach (next in adjLst[start]) {
if (color[next] == WHITE) {
dfsSearch(adjLst, n, next, color, ccNum, cc);
}
}
color[start] = BLACK;
}
Joost-Pieter Katoen
Datenstrukturen und Algorithmen
36/36
Herunterladen