Kapitel 10 Algorithmen auf Graphen

Werbung
Technische Universität München
Technische Universität München
Kapitel 10 Algorithmen auf Graphen
Motivation: Graphen sind Datenstrukturen, die in der Praxis in sehr
vielen Bereichen auftreten, u.a. Routenplanen, Kommunikation im
Internet, Streckenplanung im Schienenverkehr, Planung von
Leiterbahn-Entwürfen im Chipdesign, Planung von Materialflüssen
in der Logistik und Produktion etc.
Zur Erinnerung
•  Ein Graph ist ein Tupel G = (E, V) mit
–  V: Menge von Knoten (Vertices)
–  E: Menge von Kanten (Edges), (v, w) ∈ E, mit v, w ∈ V
•  Attributierter Graph:
•  Abbildung w: E → EA , EA Menge von Kanten-Gewichten
•  Abbildung a: V → EV , EV Menge von Knoten-Attributen
1
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
10.1 Breitensuche (Breadth First Search), BFS
•  Durchsuchen eines Graphen in der Breite
Idee: Gegeben sei ein Graph G = (E, V)
–  Ausgehend von einem Startknoten s ∈ V werden schrittweise
alle Knoten des Graphen aufgesucht.
–  Es wird für jeden Knoten v ∈ V der Abstand k zum Startknoten
berechnet, also die Länge des Pfades von s zu v
–  es werden zunächst alle Knoten mit Abstand k, danach
alle Knoten mit Abstand k + 1 etc. aufgesucht.
Beispiel:
Technische Universität München
Technische Universität München
BFS: Beispiel: Breitensuchbaum
Algorithmus zur Breitensuche BFS
Basis: Graph G ist bereits durch Adjazenzlisten dargestellt
BFS(G, s)
Datenstrukturen des Algorithmus
1 for alle Knoten u ∈ V[G] - {s}
•  Der Bearbeitungszustand von Knoten
2
farbe[u] = WEISS
3
d[u] = ∞
wird über das Attribut „farbe“ gespeichert:
4
π[u] = NIL
schwarz: bearbeitet; weiß: noch nicht aufgesucht;
grau: aufgesucht, aber noch nicht abschließend
bearbeitet
•  Für jeden Knoten v ∈ V:
–  farbe(v) enthält seine Farbe
–  π(v) ist der Vorgänger-Knoten
–  d(u) ist der Abstand zur Wurzel s
–  FIFO-Warteschlange Q mit grauen Knoten
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
2
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
3
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
5
6
7
8
9
10
11
12
13
14
15
16
17
18
farbe[s] = GRAU
d[s] = 0
π[s] = NIL
Q=Ø
ENQUEUE(Q, s)
while Q ≠ Ø
u = DEQUEUE(Q)
for alle v ∈ Adj[u]
if farbe[v] == WEISS
farbe[v] = GRAU
d[v] = d[u] + 1
π[v] = u
ENQUEUE(Q, v)
farbe[u] = SCHWARZ
4
Technische Universität München
Beispiel: Gegeben sei der Graph G
BFS(G, s)
1 for alle Knoten u ∈ V[G] - {s}
2
farbe[u] = WEISS
3
d[u] = ∞
4
π[u] = NIL
5 farbe[s] = GRAU
6 d[s] = 0
7 π[s] = NIL
8 Q=Ø
9 ENQUEUE(Q, s)
10 while Q ≠ Ø
11
u = DEQUEUE(Q)
12
for alle v ∈ Adj[u]
13
if farbe[v] == WEISS
14
farbe[v] = GRAU
15
d[v] = d[u] + 1
16
π[v] = u
17
ENQUEUE(Q, v)
18
farbe[u] = SCHWARZ
Adjazenzmatrix von G
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
Technische Universität München
Der Starknoten sei s
•  s wird Wurzel des Suchbaums
Zeile 1-4: Initialisierung
•  alle v mit weiß markieren, noch nicht besucht
•  Abstand zu s noch
unklar: auf unendlich
•  Vorgänger noch unbekannt: NIL
Beispiel Fortsetzung
Erinnerung:
•  schwarz: bearbeitet
•  weiß: noch nicht aufgesucht
•  grau: nicht zu Ende bearbeitet
Zeile 5-9: Initialisiere s
•  markieren als grau, in Q
•  Abstand zu sich selbst: 0
Zeile 12-17: Bearbeite s
•  bearbeite alle direkten
Nachfolger von s
•  und deren direkte NF (gehe
5
in die Breite!)
Beispiel: Übergang von (a) zu (b)
•  schattierte Kanten (s,r), (s,w)
zu Nachfolgern von s werden
Kanten des Breitensuchbaums
•  Attribut im Knoten u: d[u]
Abstand zur Wurzel s
•  Knoten w, r sind als nächstes
zu bearbeiten: Speicherung in Q
Übergang von (b) zu (c)
•  Knoten w bearbeiten; Kanten (w,f), (w,x) in
Breitensuchbaum aufnehmen
6
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
Technische Universität München
Laufzeitanalyse von BFS:
•  Nach der Initialisierung wird kein weiterer weißer
Breitensuchbaum :
Technische Universität München
BFS(G, s)
1 for alle Knoten u ∈ V[G] - {s}
2
farbe[u] = WEISS
3
d[u] = ∞
4
π[u] = NIL
5 farbe[s] = GRAU
6 d[s] = 0
7 π[s] = NIL
8 Q=Ø
9 ENQUEUE(Q, s)
10 while Q ≠ Ø
11
u = DEQUEUE(Q)
12
for alle v ∈ Adj[u]
13
if farbe[v] == WEISS
14
farbe[v] = GRAU
15
d[v] = d[u] + 1
16
π[v] = u
17
ENQUEUE(Q, v)
18
farbe[u] = SCHWARZ
Knoten mehr aufgenommen, deshalb stellt der
•  Test in Zeile 13 sicher, dass jeder Knoten nur
einmal in Q eingefügt wird:
Einfügen erfordert O(1).
•  Jeder Knoten wird damit auch höchstens
einmal aus Q wieder entnommen:
Entnehmen erfordert O(1).
Damit gilt: Laufzeit der Operationen auf Q: O(|V|).
•  Die Adjazenzliste eines Knotens v wird bei Entnahme des Knotens
aus Q geprüft, also nur einmal durchlaufen
•  Laufzeit zur Prüfung aller Adjazenzlisten ist: O(|E|)
C-Implementierung der Breitensuche BFS
void BreadthFirstSearch(int origin, int destination)
{
Queue *q = new Queue();
StartQueue(q);
Enqueue(q, origin);
while(IsQueueEmpty(q) == 0)
{
int u = Dequeue(q);
if(u == destination)
{
printf("Path found.");
break;
}
//………continued
Damit ergibt sich die Gesamtlaufzeit von BFS: O(|V| + |E|)
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
7
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
8
Technische Universität München
Technische Universität München
C-Implementierung der Breitensuche BFS
C-Implementierung der Breitensuche BFS
else
else
{
{
visited[u] = 1;
printf("Queue full.");
for(int v = 1; v <= 20; v++)
{
if(map[u][v] != 0)
{
if(visited[v] == 0)
{
visited[v] = 1;
break;
}
}
else
{
ShowPath(v);
return;
parents[v] = u;
}
}
if(v != destination)
{
if(!IsQueueFull(q))
{
Enqueue(q, v);
}
}
}
}
}
ShowPath(v);
printf("\n");
}
//………continued
9
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
Technische Universität München
Technische Universität München
10.2 Tiefensuche (Depth First Search), DFS
Idee: Gegeben sei ein Graph G = (E, V)
•  Startknoten s: eine Kante (s, u) wird ausgewählt und der Knoten u
wird weiter bearbeitet; falls s weitere Nachfolger hat, werden diese
‚vorgemerkt‘ auf Stack (für Backtracking).
•  Für u analoges Vorgehen: Auswahl einer Kante (u,r) und
bearbeiten von r, alternative Wege werden ‚vorgemerkt‘.
•  Falls r schon fertig bearbeitet ist, dann zurück zum letzten Verzweigungspunkt (Stack-pop) und mit dem Knoten weitermachen
Beispiel
1 
2
3
4
5
6
Startkonten sei s= 1
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
10
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
11
•  Nutzung von zwei zusätzlichen Markierungen: Werte 1 ≤ x ≤ 2|V|
–  Zeitmarke, wann Knoten a entdeckt und grau gefärbt wurde, in d[a]
–  Zeitmarke, wann seine adjazenten Knoten bearbeitet sind und a schwarz wurden, f[a]
•  Eingabe: gerichteter oder ungerichteter Graph G
DFS(G)
1 for alle Knoten a ∈ V[G]
2
farbe[a] = WEISS
3
π[a] = NIL
4 zeit = 0
5 for alle Knoten a ∈ V[G]
6
if farbe[a] == WEISS
7
DFS-VISIT(a)
DFS-VISIT(a)
1 farbe[a] = GRAU // Ein weißer Knoten a wurde entdeckt.
2 zeit = zeit + 1
3 d[a] = zeit
4 for alle b ∈ Adj[a] // Verfolge die Kante (a, b).
5
if farbe[b] == WEISS
6
π[b] = a
7
DFS-VISIT(a)
8 farbe[a] = SCHWARZ // a wird geschwärzt und ist abgearbeitet.
9 f[a] = zeit = zeit + 1
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
12
Technische Universität München
Technische Universität München
Laufzeit von DFS:
•  Zeile 1-3, 5-7 (ohne VISIT): Θ(|V|)
•  |V| mal Prozedur VISIT,
•  In der Prozedur Visit: Zeile 4-7 |Adj(v)| mal durchlaufen.
Beispiel:
wegen
gilt für die Laufzeit von VISIT : Θ(|E|)
•  Gesamtlaufzeit DFS: Θ(|V| + |E|), gleiche Laufzeit wie BFS
DFS(G)
1 for alle Knoten a ∈ V[G]
2
farbe[a] = WEISS
3
π[a] = NIL
4 zeit = 0
5 for alle Knoten a ∈ V[G]
6
if farbe[a] == WEISS
7
DFS-VISIT(a)
13
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
DFS-VISIT(a)
1 farbe[a] = GRAU // Ein weißer Knoten a wurde entdeckt.
2 zeit = zeit + 1
3 d[a] = zeit
4 for alle b ∈ Adj[a] // Verfolge die Kante (a, b).
5
if farbe[b] == WEISS
6
π[b] = a
7
DFS-VISIT(a)
8 farbe[a] = SCHWARZ // a wird geschwärzt und ist abgearbeitet.
9 f[a] = zeit = zeit + 1
Technische Universität München
Technische Universität München
10.3 Minimaler Spannbaum (spanning tree), MST
•  In der Praxis sehr häufig verwendete Verfahren, um kostengünstige, zusammenhängende Netzwerke zu erstellen:
z.B. Telefonnetz, elektrische Schaltungen, bei Rechnernetzen:
Protokoll, um (Endlos-)Schleifen und redundante Pfade in
geswitchten LANs zu vermeiden, etc.
Definition: Minimaler Spannbaum
•  Gegeben sei ein ungerichteter, zusammenhängender
Graph G = (E, V) und eine Gewichtsfunktion w: E → ℝ.
•  Für jede Kante (u, v) ∈ E ist ein Kanten-Gewicht w(u, v)
gegeben, das die Kosten für die Verbindung von u mit v beschreibt.
•  Ein Minimaler Spannbaum von G ist ein Graph MST = (T, V) mit
•  einer Menge von Kanten T ⊆ E, so dass gilt:
•  T enthält keine Zyklen und
•  verbindet alle Knoten aus V und
•  das Gesamtgewicht w(T), mit
ist minimal.
•  MST ist ein Baum, er wird als Spannbaum von G bezeichnet.
Beispiel: Ungerichteter Graph G und sein MST
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
Frage:
wie ist ein MST definiert und wie bestimmt man ihn?
14
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
15
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
16
Technische Universität München
Technische Universität München
Beispiel: Minimaler Spannbaum eines ungerichteten Graphen
•  Im Beispiel bilden die schattierten Kanten den minimalen
Spannbaum.
•  Die Kanten sind mit ihren Gewichten attributiert.
•  Gesamtgewicht des Baums?
Aufbau eines minimalen Spannbaums
Zwei Standardalgorithmen zur Bestimmung eines MST:
•  Algorithmus von Prim und Algorithmus von Kruskal.
•  Beide Algorithmen arbeiten nach der Greedy-Strategie.
•  Beide Algorithmen benötigen eine Laufzeit: O(|E| log2 |V|), wenn
als Datenstrukturen binäre Heaps verwendet werden.
10.3.1 Greedy-Strategie
•  Anwendbar in Algorithmen, die aus verschiedenen Möglichkeiten
eine auswählen müssen.
•  Geedy (gierig) Ansatz: Auswahl der aktuell besten Möglichkeit.
•  Eine solche Strategie garantiert aber nicht, dass auch ein globales
Optimum gefunden wird!
Bem.: Minimaler Spannbaum ist nicht eindeutig.
Alternativer Spannbaum mit gleichem
minimalem Gesamtgewicht?
17
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
18
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
Technische Universität München
Technische Universität München
Generischer (allgemeiner) Algorithmus MST:
•  Hilfsdatenstruktur A, die eine Kantenmenge repräsentiert, die eine
Teilmenge des minimalen Spannbaumes ist.
•  In jedem Schritt wird eine Kante (u, v) bestimmt, die der Menge A
hinzugefügt werden kann, ohne die Eigenschaft von A zu verletzen.
•  Eine solche Kante nennen wir sichere Kante.
Beispiel: Vorgehen gemäß der Greedy-Strategie
GENERIC-MST(G, w)
1 A={}
2 while A bildet keinen Spannbaum
3
bestimme eine Kante (u, v), die sicher für A ist
4
A = A ∪ {(u, v)}
5 return A
Zeile 3 des Algorithmus erfordert Regeln, um eine geeignete
Kante zu bestimmen.
Der Algorithmus von Kruskal legt hierfür eine bestimmte Regel fest.
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
19
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
20
Technische Universität München
Technische Universität München
10.3.2 Algorithmus von Kruskal
Vorab-Bemerkungen
Gegeben sei ein Graph G = (E,V).
•  G besteht aus n Zusammenhangskomponenten Gi=(Ei,Vi),
i ∈ {1, .., n}, wobei gilt: E = E1 ∪ E2 ∪ … ∪ En , V = V1 ∪ V2 ∪ … ∪ Vn
und jeder Graph Gi ist zusammenhängend
•  falls G ein Baum ist, dann ist n=1.
Für den Kruskal-Algorithmus gilt: die Hilfsdatenstruktur A
ist eine Menge von Zusammenhangskomponenten
Beispiel:
Graph mit 4 Zusammenhangskomponenten
21
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
Algorithmus von Kruskal
•  Bestimmung der zu A hinzuzufügenden sicheren Kante:
•  Wähle von allen Kanten, die zwei Bäume des Waldes verbinden, eine Kante (u, v) mit dem kleinsten Gewicht aus.
Idee:
(1)  Sortiere die Kanten nach ihren Gewichten. Aufwand?
(2) Test für eine Kante (u, v):
•  Verbindet die Kante zwei Bäumen und macht daraus einen
•  oder erzeugt sie einen Kreis im Graph?
Kreise sind nicht erwünscht!
Beispiel:
Technische Universität München
Technische Universität München
Algorithmus von Kruskal (Forts.)
Aus dem zuvor Gesagten folgt: Der Algorithmus benötigt
Datenstrukturen,
1. mit denen für jede Kante (u, v) ∈ E effizient entschieden werden
kann, ob u und v in derselben Zusammenhangskomponente
von G liegen, und
2. die die Zusammenhangskomponenten effizient verschmelzen.
Lösung: Union-Find-Datenstruktur für disjunkte, dynamische
Mengen: Find: Lösung für Aufgabe (1.) von oben
Union: Lösung für Aufgabe (2.)
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
22
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
23
Union-Find-Datenstruktur
•  Gegeben sei eine Menge U von Elementen. Verwaltet wird eine
Familie {S1, S2, …, Sk} von disjunkten Teilmengen von U.
•  jede Teilmenge Si wird identifiziert durch ein Element aus Si, das
ist ein Repräsentant von Si.
Folgende Operationen werden benötigt:
•  MAKE-SET(x): 1-elementige Menge
erzeugt Teilmenge {x} mit Repräsentant x.
•  FIND-SET(x):
liefert den Repräsentant derjenigen Menge, die x enthält.
•  UNION(x, y):
Vereinigen der Teilmengen, die x bzw. y enthalten.
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
24
Technische Universität München
Technische Universität München
Realisierung einer Union-Find-Datenstruktur
z.B. mit Verketteten Listen:
•  Jede Teilmenge Si wird als eine verkettete Liste Si der
Elemente in Si repräsentiert.
•  Der Repräsentant von Si ist das erste Element von Si.
•  Für jedes Listenelement: verwalten eines Verweises auf
den Repräsentanten rep(x) der Liste.
Beispiel:
Realisierung der Operationen mittels der verketteten Liste
MAKE-SET(x)
•  MAKE-SET(x):
erzeugen einer 1-elementigen Liste,
Laufzeit O(1).
•  FIND-SET(x):
Ausgabe des Repräsentanten rep(x),
Laufzeit O(1).
1
2
3
rep[x] = x
next[x] = NIL
size[x] = 1
FIND-SET(x)
1 return rep[x]
•  UNION(x, y): Sx enthalte x und Sy enthalte y.
(1) Bestimme die kürzere der beiden Listen Sx, Sy.
(2) Hänge kürzere Liste an längere Liste an.
(3) ersetze Repräsentanten für die Elemente der kürzeren Liste.
Laufzeit proportional zur Länge der kürzeren Liste.
25
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
26
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
Technische Universität München
Technische Universität München
C-Implementierung einer Union-Find-Datenstruktur
mit verketteten Listen
C-Implementierung einer Union-Find-Datenstruktur
mit verketteten Listen
// the union_find.c file
#include <stdlib.h>
// the union_find.h file
#include "union_find.h"
#ifndef _UNION_FIND_H_
#define _UNION_FIND_H_
forest_node* MakeSet(void* value) {
forest_node* node = malloc(sizeof(forest_node));
node->value = value;
node->parent = NULL;
node->rank = 0;
return node;
}
typedef struct forest_node_t {
void* value;
struct forest_node_t* parent;
int rank;
} forest_node;
forest_node* MakeSet(void* value);
void Union(forest_node* node1, forest_node* node2);
forest_node* Find(forest_node* node);
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
void Union(forest_node* node1, forest_node* node2) {
if (node1->rank > node2->rank) {
node2->parent = node1;
} else if (node2->rank > node1->rank) {
node1->parent = node2;
} else { /* they are equal */
node2->parent = node1;
node1->rank++;
}
}
//…………… continued
27
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
28
Technische Universität München
Technische Universität München
Put it all together: Algorithmus von Kruskal
•  Benutzung einer Union-Find-Datenstruktur A, um die Zusammenhangskomponenten (hier Bäume) von G zu verwalten.
•  Test, ob eine Kante (u, v) zwei Zusammenhangskomponenten
verbindet, durch Vergleich: FIND-SET(u) == FIND-SET(v)?
•  Verschmelzen von Zusammenhangskomponenten durch UNION.
C-Implementierung einer Union-Find-Datenstruktur
mit verketteten Listen
// the union_find.c file
forest_node* Find(forest_node* node) {
forest_node* temp;
/* Find the root */
forest_node* root = node;
while (root->parent != NULL) {
root = root->parent;
}
/* Update the parent pointers */
while (node->parent != NULL) {
temp = node->parent;
node->parent = root;
node = temp;
}
return root;
}
MST-KRUSKAL(G, w)
1 A={}
2 for alle Knoten v ∈ V[G]
3
MAKE-SET(v)
4 sortiere die Kanten E in nichtfallender Reihenfolge nach dem Gewicht w
5 for alle Kanten (u, v) ∈ E
6
if FIND-SET(u) ≠ FIND-SET(v)
7
A = A ∪ {(u, v)}
8
UNION(u, v)
9 return A
29
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
Technische Universität München
Technische Universität München
Beispiel:
Start mit
n Teilbäumen, mit
|V| = n, also jeder Knoten wird als ein eigener Teilbaum betrachtet.
n-mal, wird die Operation MAKE-SET aufgerufen (Zeilen 2-3)
Zeile 4: Sortieren der Kanten E= {(h,g), (g,f), (i,c), (a,b),(c,f), … }
MST-KRUSKAL(G, w)
Zeilen 5-8: bearbeite Kante (h,g)
1
2
3
4
5
6
7
8
9
A={}
for alle Knoten v ∈ V[G]
MAKE-SET(v)
sortiere die Kanten E in nichtfallender Reihenfolge nach dem Gewicht w
for alle Kanten (u, v) ∈ E
if FIND-SET(u) ≠ FIND-SET(v)
A = A ∪ {(u, v)}
UNION(u, v)
return A
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
30
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
31
Beispiel: Forts.
MST-KRUSKAL(G, w)
1 A={}
2 for alle Knoten v ∈ V[G]
3
MAKE-SET(v)
4 sortiere die Kanten E
in nichtfallender
Reihenfolge nach
dem Gewicht w
5 for alle Kanten (u, v) ∈ E
6
if FIND-SET(u) ≠ FIND-SET(v)
7
A = A ∪ {(u, v)}
8
UNION(u, v)
9 return A
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
32
Technische Universität München
Technische Universität München
Laufzeit des Kruskal Algorithmus:
•  Zeile 1: Initialisierung der Menge A: O(1)
•  Zeile 2-3: |V| mal MAKE-SET Operation
•  Zeile 4: Sortieren der Kanten: O(|E| log2|E|).
•  Es gibt höchstens |E| FIND-SET und |V| – 1 UNION Operationen.
pro Kante: Herausfinden, ob Kreis geschlossen wird (FIND-SET)
Verbinden der Teilbäume (UNION)
Gesamtlaufzeit: O(|V| * UNION + |E| * Find + |E| * log2|E|) ,
•  Implementierung mit Heaps: FIND: O(log (|E|)), UNION: O(log2(|V|)),
also: O(|V| * log2(|V|) + |E| * log2 (|E|) + |E| * log2|E|)
Man kann zeigen: TKruskal = O(|E| log2|V|).
Beispiel (Forts.)
Bem. Der Algorithmus von Prim arbeitet auf einem Baum, statt auf
Wäldern; Nutzung von Prioritäten-Warteschlange
33
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
Technische Universität München
Technische Universität München
C-Implementierung des Algorithmus von Kruskal
C-Implementierung des Algorithmus von Kruskal
#include <stdio.h>
#include <stdlib.h>
#define MAX_EDGE 10000
#define MAX_VERTEX 100000
void Kruskal(int n, int m) {
int i, k;
for ( i = 0, k = 0 ; i < m, k < n - 1 ; i++ ) {
if ( Find(edge[i].v1) != Find(edge[i].v2) ) {
mst[k] = edge[i];
Union(edge[i].v1, edge[i].v2);
k++;
}
}
struct Edge {
int v1, v2;
double weight;
};
struct Set {
int parent, rank;
};
}
void Union(int a, int b) {
int aRoot, bRoot;
aRoot = Find(a); bRoot = Find(b);
if ( set[aRoot].rank < set[bRoot].rank ) set[aRoot].parent = bRoot;
else if ( set[aRoot].rank > set[bRoot].rank ) set[bRoot].parent = aRoot;
else if ( aRoot != bRoot ) {
set[bRoot].parent = aRoot;
set[aRoot].rank++;
}
}
typedef struct Edge Edge;
typedef struct Set Set;
Edge edge[MAX_EDGE], mst[MAX_EDGE];
Set set[MAX_VERTEX];
void Kruskal(int, int);
void Union(int, int);
int Find(int);
void MakeSet(int);
int compare(void const*, void const*);
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
34
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
35
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
36
Technische Universität München
Technische Universität München
C-Implementierung des Algorithmus von Kruskal
C-Implementierung des Algorithmus von Kruskal
int Find(int a) {
if ( set[a].parent == a ) return a;
else {
set[a].parent = Find(set[a].parent);
return set[a].parent;
}
}
int main() {
int n, m;
int i;
//scanf("%d %d", &n, &m);
for ( i = 0 ; i < m ; i++ ) scanf("%d %d %lf", &edge[i].v1, &edge[i].v2, &edge[i].weight);
MakeSet(n);
qsort(edge, m, sizeof(Edge), compare);
Kruskal(n, m);
for ( i = 0 ; i < n - 1 ; i++ ) printf("%d %d %lf\n", mst[i].v1, mst[i].v2, mst[i].weight);
return 0;
void MakeSet(int n) {
int i;
for ( i = 0 ; i < n ; i++ ) {
set[i].parent = i;
set[i].rank = 0;
}
}
}
int compare(const void *a, const void *b) {
if ( (*(Edge*)a).weight < (*(Edge*)b).weight ) return -1;
else if ( (*(Edge*)a).weight == (*(Edge*)b).weight ) return 0;
else return 1;
}
37
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
38
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
Technische Universität München
Technische Universität München
10.4 Kürzeste Pfade
10.4.1 Grundlagen
•  Gegeben sei ein gewichteter, gerichteter Graph G = (E, V) mit der
Gewichtsfunktion w: E → ℝ.
•  Das Gewicht eines Pfades p= ( v0, v1, …, vk) ist die Summe der
Gewichte aller seiner Kanten, also:
•  Das Gewicht des kürzesten Pfades von u nach v ist definiert durch:
Beispiele für Gewichte: Entfernungen, Kosten, Zeit, Ressourcen, …
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
39
Anwendungsbeispiel: Kürzester Pfad
Routenplaner: Straßenkarte von Deutschland
–  Knoten sind Großstädte
–  Kanten sind Autobahnverbindungen
300
–  Kantengewichte stellen die Fahrstrecken
dar
HH
150
B
250
H
200
200
350
mögliche Fragestellungen
K
–  der kürzeste Weg von München (M)
200
F
300
nach Hamburg (HH) ?
150
–  Was sind die kürzesten Verbindungen
KA
von München zu allen anderen
50 S
deutschen Großstädten ?
250
–  Was sind die kürzesten Verbindungen
zwischen allen deutschen Großstädten ?
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
200
450
D
200
300
N
150
M
40
Technische Universität München
Technische Universität München
Beispiel: Kürzester Pfad (Forts.)
kürzester Pfad von Startknoten S zum Zielknoten Z:
HH
Pfad P* mit minimalem Gewicht w(P*)
200
150
300
w(PM,B) = 150 + 200 + 450 = 800
H
w(PM,B) = 150 + 300 + 200 = 650
w(PM,B) = 250 + 150 + 350 + 250 = 1.000
200
K
200
300
P*M, B = (M, N, D, B)
B
250
200
350
450
D
F
200
150
KA
50
300
N
S
150
250
M
41
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
Bekannte Algorithmen zur Berechnung kürzester Pfade:
•  Kürzeste Pfade in einem Graphen mit gegebenem Startknoten s:
•  Dijkstra-Algorithmus (nur positive Kantengewichte):
Beschreibung in 10.4.2. Laufzeit O(|E| * log2 |V|).
•  Bellman-Ford-Algorithmus (auch negative Gewichte):
Algorithmus bestimmt immer kleiner werdende Schätzwerte
für das Gewicht des kürzesten Pfades von s zu allen anderen
Knoten v des Graphen, bis kürzester Pfad ohne negative
Zyklen erreicht. Laufzeit O(|V| * |E|).
•  Kürzeste Pfade in einem Graphen zwischen allen Knotenpaaren
•  Floyd-Warshall-Algorithmus (All Pairs Shortest Path Problem)
Basis: Prinzip der dynamischen Programmierung. Zeit: Θ(|V|3)
Technische Universität München
Satz: Teilpfade von kürzesten Pfaden sind auch kürzeste Pfade.
Beweis:
•  Sei P = (vS, ... vi, ... vj, ... vz ) ein kürzester Pfad von Knoten vS
zum Knoten vz.
•  Sei Pij = (vi, vi+1, ..., vj) der Teilpfad in P von vi nach vj
•  Es gilt w(P) = w(PSi) + w(Pij) + w(Pjz)
Ann.: P*ij sei eine Abkürzung von vi nach vj, d.h. w(P*ij) < w(Pij),
dann gilt: w(P) = w(PSi) + w(Pij) + w(Pjz)
> w(PSi) + w(P*ij) + w(Pjz) = w(P‘)
PSi
Pij
PjZ
Widerspruch zur AnvS
vZ
vi
vj
nahme, denn dann
wäre P kein kürzester Pfad,
sondern P‘ wäre kürzer.
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
43
Pij*
42
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
Technische Universität München
10.4.2 Dijkstra-Algorithmus
Gegeben Graph G=(E,V) und Startknoten s.
Bestimme kürzesten Pfad von s zu allen Knoten v ∈ V
Einsatzgebiete u.a.
•  Routenplaner: Graph repräsentiert das Straßennetz,
•  Im Internet als Routing-Algorithmus (Wegewahl) im OSPF- und
OLSR-Protokoll (für mobile drahtlose LANs, mobile Ad-hoc Netze)
eingesetzt.
Beispiel: Routing von Daten im Internet
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
44
Technische Universität München
Technische Universität München
Basis des Dijkstra-Algorithmus:
•  Gerichteter, gewichteter Graph mit nicht-negativen Kantengewichten.
•  Hilfsdatenstruktur S: Menge von Knoten, deren Gewichte der
kürzesten Pfade von s aus bereits abschließend bestimmt wurden.
•  Hilfsdatenstruktur Q: Min-Prioritätenwarteschlange für Knoten
Dijkstra arbeitet nach Greedy-Strategie und mit der Methode
der Relaxation:
Relaxation:
•  für jeden Knoten v ∈ V wird ein Attribut d[v] verwaltet, das ist die
Schätzung des kürzesten Pfades von s zu v (obere Schranke für
Gewicht des kürzesten Pfades).
45
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
Relaxieren einer Kante (u, v):
• Testen, ob der bisher gefundene kürzeste Pfad nach v noch
verbessert werden kann, indem über den Knoten u gegangen wird.
Relaxationsschritt:
•  für jeden Knoten v ∈ V wird ein Attribut d[v] verwaltet, d[v] ist die
INITIALIZE-SINGLE-SOURCE(G, s)
Schätzung des kürzesten Pfades von s zu v
1 for alle Knoten v ∈ V[G]
2
d[v] = ∞
•  Eine solche Schätzung wird initialisiert:
3
π[v] = NIL
4 d[s] = 0
Nach der Initialisierung gilt:
•  Der Vorgängerknoten π[v] = NIL für alle v ∈ V,
•  d[s] = 0 und
•  d[v] = ∞ für alle v ∈ V – {s}
46
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
Technische Universität München
Technische Universität München
Pseudocode für einen Relaxationsschritt auf der Kante (u,v):
Beispiel: Relaxieren einer Kante (u, v) mit dem Gewicht w(u, v) = 2.
In (a) verringert sich die Schätzung, in (b) nicht.
RELAX(u, v, w)
1 if d[v] > d[u] + w(u, v)
2
d[v] = d[u] + w(u, v)
3
π[v] = u
Beispiel
Bem.: der Dijkstra-Algorithmus relaxiert jede Kante genau einmal.
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
47
•  In jedem Knoten ist seine Schätzung des kürzesten Pfades eingetragen.
•  (a) vor der Relaxation gilt: d[v] > d[u] + w(u, v),
d.h. es verringert sich der Wert von d[v].
•  (b) vor der Relaxation gilt: d[v] ≤ d[u] + w(u, v), so dass sich
der Wert von d[v] nicht verändert.
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
48
Technische Universität München
Technische Universität München
Dijkstra-Algorithmus:
•  Eingabe: gerichteter Graph und Gewichtsfunktion w
•  Vom Startknoten s werden die kürzest möglichen Wege weiterverfolgt.
•  Dazu wird in jedem Schritt der Knoten u ∈ V – S ausgewählt, der die
kleinste Schätzung des kürzesten Pfades besitzt,
•  u wird S hinzugefügt und alle Kanten v, die von u abgehen, werden
relaxiert.
DIJKSTRA(G, w, s)
1 INITIALIZE-SINGLE-SOURCE(G, s)
2 S=Ø
3 Q = V[G]
4 while Q ≠ Ø
5
u = EXTRACT-MIN(Q)
6
S = S ∪ {u}
7
for alle Knoten v ∈ Adj[u]
8
RELAX(u, v, w)
Beispiel: Startknoten s
•  die Schätzungen der kürzesten Pfade
sind in Knoten eingetragen.
•  Schwarze Knoten gehören zur Menge S.
•  Weiße Knoten werden in der MinPrioritätenwarteschlange Q verwaltet.
RELAX(u, v, w)
1 if d[v] > d[u] + w(u, v)
2
d[v] = d[u] + w(u, v)
3
π[v] = u
INITIALIZE-SINGLE-SOURCE(G, s)
1 for alle Knoten v ∈ V[G]
2
d[v] = ∞
3
π[v] = NIL
4 d[s] = 0
INITIALIZE-SINGLE-SOURCE(G, s)
1 for alle Knoten v ∈ V[G]
2
d[v] = ∞
3
π[v] = NIL
4 d[s] = 0
RELAX(u, v, w)
1 if d[v] > d[u] + w(u, v)
2
d[v] = d[u] + w(u, v)
3
π[v] = u
49
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
DIJKSTRA(G, w, s)
1 INITIALIZE-SINGLE-SOURCE(G, s)
2 S=Ø
3 Q = V[G]
4 while Q ≠ Ø
5
u = EXTRACT-MIN(Q)
6
S = S ∪ {u}
7
for alle Knoten v ∈ Adj[u]
8
RELAX(u, v, w)
Technische Universität München
Beispiel: Forts.
DIJKSTRA(G, w, s)
1 INITIALIZE-SINGLE-SOURCE(G, s)
2 S=Ø
3 Q = V[G]
4 while Q ≠ Ø
5
u = EXTRACT-MIN(Q)
6
S = S ∪ {u}
7
for alle Knoten v ∈ Adj[u]
8
RELAX(u, v, w)
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
50
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
Technische Universität München
RELAX(u, v, w)
1 if d[v] > d[u] + w(u, v)
2
d[v] = d[u] + w(u, v)
3
π[v] = u
Beispiel: Forts.
51
DIJKSTRA(G, w, s)
1 INITIALIZE-SINGLE-SOURCE(G, s)
2 S=Ø
3 Q = V[G]
4 while Q ≠ Ø
5
u = EXTRACT-MIN(Q)
6
S = S ∪ {u}
7
for alle Knoten v ∈ Adj[u]
8
RELAX(u, v, w)
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
RELAX(u, v, w)
1 if d[v] > d[u] + w(u, v)
2
d[v] = d[u] + w(u, v)
3
π[v] = u
52
Technische Universität München
Beispiel: Forts.
DIJKSTRA(G, w, s)
1 INITIALIZE-SINGLE-SOURCE(G, s)
2 S=Ø
3 Q = V[G]
4 while Q ≠ Ø
5
u = EXTRACT-MIN(Q)
6
S = S ∪ {u}
7
for alle Knoten v ∈ Adj[u]
8
RELAX(u, v, w)
Technische Universität München
Nach der Terminierung des Dijkstra- Algorithmus:
Für alle v ∈ V gilt:
•  d[v]: minimaler Abstand von v zum Startknoten s
Gewicht des kürzesten Pfades
•  π[v]: Zeiger auf den Vorgänger
•  Kürzester Pfad von v zu s:
π[v] → π[π[v]] ... s
RELAX(u, v, w)
1 if d[v] > d[u] + w(u, v)
2
d[v] = d[u] + w(u, v)
3
π[v] = u
Beispiel: Kürzester Pfad von x zu s
53
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
Technische Universität München
Laufzeitanalyse des Dijkstra-Algorithmus
•  Operationen auf der Warteschlange Q:
•  Insert (Zeile 3), Extract-Min (Zeile 5)
•  Decrease-Key (Zeile 8)
Technische Universität München
DIJKSTRA(G, w, s)
1 INITIALIZE-SINGLE-SOURCE(G, s)
2 S=Ø
3 Q = V[G]
4 while Q ≠ Ø
5
u = EXTRACT-MIN(Q)
6
S = S ∪ {u}
7
for alle Knoten v ∈ Adj[u]
8
RELAX(u, v, w)
•  Insert und Extract-Min werden für jeden Knoten einmal
aufgerufen: bei |V| Knoten also |V| Oinsert + |V| OExtract-Min
•  Jeder Knoten u wird einmal zu S hinzugefügt, so dass
•  jede Kante aus Adj[u] in der for-Schleife (Zeile 7-8)
genau einmal untersucht wird.
•  Es gibt insgesamt |E| Kanten, d.h. entsprechend viele
Iterationen der for-Schleife sind erforderlich,
also höchstens |E| Decrease-Key Operationen.
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
54
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
Eine mögliche Implementierung und deren Laufzeit
Die Knoten des Graphen seien von 1 bis |V| nummeriert.
•  d[v] sei an der v-ten Position eines Feldes A gespeichert,
also A[v] = d[v]
•  dann benötigt jede Insert und Decrease-Key Operation O(1).
•  Extract-Min erfordert O(|V|), da das Feld durchsucht werden
muss, also
Gesamtlaufzeit Dijkstra-Algorithmus: O(|V|2 + |E|) = O(|V|2)
Beispiel:
55
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
56
Technische Universität München
Technische Universität München
Laufzeitverbesserungen durch geschickte Implementierung:
•  mit Min-Heap statt Prio-Warteschlange,
•  für Graphen mit wenigen Kanten sehr gut geeignet:
•  Extract-Min (|V| mal), und
Decrease-Key (|E| mal) : O(log2 |V|).
•  Gesamtlaufzeit:
O((|V| + |E|) * log2 |V|).
Vereinfacht zu:
O(|E| * log2 |V|), falls alle Knoten von Startknoten erreichbar.
C-Implementierung des Algorithmus von Dijkstra
#include <stdlib.h>
#include "bool.h"
#include "wgraph.h"
#define MAXINT 100007
int parent[MAXV];
/* discovery relation */
dijkstra(graph *g, int start)
{
int i,j;
bool intree[MAXV];
int distance[MAXV];
int v;
int w;
int weight;
int dist;
/* counters */
/* is the vertex in the tree yet? */
/* distance vertex is from start */
/* current vertex to process */
/* candidate next vertex */
/* edge weight */
/* best current distance from start */
for (i=1; i<=g->nvertices; i++) {
intree[i] = FALSE;
distance[i] = MAXINT;
parent[i] = -1;
}
distance[start] = 0;
v = start;
57
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
58
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
Technische Universität München
Technische Universität München
C-Implementierung des Algorithmus von Dijkstra
C-Implementierung des Algorithmus von Dijkstra
while (intree[v] == FALSE) {
intree[v] = TRUE;
for (i=0; i<g->degree[v]; i++) {
w = g->edges[v][i].v;
weight = g->edges[v][i].weight;
if (distance[w] > (distance[v]+weight)) {
distance[w] = distance[v]+weight;
parent[w] = v;
}
}
main()
{
graph g;
int i;
read_graph(&g,FALSE);
dijkstra(&g,1);
for (i=1; i<=g.nvertices; i++)
find_path(1,i,parent);
printf("\n");
v = 1;
dist = MAXINT;
for (i=1; i<=g->nvertices; i++)
if ((intree[i] == FALSE) && (dist > distance[i])) {
dist = distance[i];
v = i;
}
}
}
}
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
59
AuD, WS11/12, C. Eckert &Th. Stibor, Kapitel 10 Algorithmen auf Graphen
60
Herunterladen