Algorithmen und Datenstrukturen

Werbung
Wiederholung Graph
gerichteter Graph G = (V , E) mit E ⊆ {(u, v ) | u, v ∈ V }
ungerichteter Graph G = (V , E) mit
E ⊆ {{u, v } | u, v ∈ V ∧ u 6= v }
Graph mit Knotenmarkierung in Menge CV
(gerichtet oder ungerichtet)
G = (V , E, lV ) mit lV : V → CV
Graph mit Kantenmarkierung in Menge CE
(gerichtet oder ungerichtet)
G = (V , E, lE ) mit lE : E → CE (Gewichte)
Repräsentation als
I
Diagramm (i.A. zur maschinellen Verarbeitung untauglich)
I
(Adjazenz-)Matrix (sinnvoll für dichte Graphen)
explizite Darstellung der Relation:
I
I
I
Liste von Kanten
Adjazenzliste (Knoten → Liste aller Nachfolger)
198
Teilgraphen
Teilgraph in G = (V , E):
Graph G0 = (V 0 , E 0 ) mit V 0 ⊆ V und E 0 ⊆ E
induzierter Teilgraph einer Knotenmenge V 0 ⊆ V in G = (V , E):
Graph G0 = (V 0 , E 0 ) mit E 0 = E ∩ (V 0 )2
Weg in G = (V , E): Folge (p1 , . . . , pn ) ∈ V n mit
∀i ∈ {1, . . . , n − 1} : (pi , pi+1 ) ∈ E
Weg von u nach v in G:
Weg (p1 , . . . , pn ) in G mit p1 = u und pn = v
Pfad in G = (V , E):
(gerichteter) Teilgraph P = (V 0 , E 0 ) in G mit
V 0 = {p1 , . . . , pn }, E 0 = {(pi , pi+1 ) | i ∈ {1, . . . , n − 1}}
(Pfad von p1 nach pn )
Kreis in G = (V , E):
(gerichteter) Teilgraph C = (V 0 , E 0 ) in G mit
V 0 = {p1 , . . . , pn } und
E 0 = {(pi , pi+1 ) | i ∈ {1, . . . , n − 1}} ∪ {(pn , p1 )}
199
Zusammenhangskomponenten eines Graphen
(gerichteter oder ungerichteter) Graph G heißt
zusammenhängend gdw. ∀(u, v ) ∈ V 2 existiert ein Pfad
zwischen u und v
Zusammenhangskomponente eines ungerichteten Graphen
G = (V , E):
⊆-maximale Knotenmenge V 0 ⊆ V , so dass der von V 0
induzierte Teilgraph von G zusammenhängend ist
200
Wiederholung Baumdurchquerungen
(für Bäume beliebiger Knotengrade)
Spezifikation Baumdurchquerung:
V: Eingabe Baum t mit Wurzel s
N: Ausgabe Folge (x1 , . . . , xn ) (lineare DS) mit
1. {x1 , . . . , xn } = alle (inneren) Knoten in t
2. ∀i, j ∈ {1, . . . , n} : i 6= j → xi 6= xj ,
Allgemeiner Durchquerungs-Algorithmus
( mit Menge La der noch zu besuchenden Knoten):
Algorithmus : Baum-Durchquerung
Eingabe : Baum t mit Wurzel s
Ausgabe : x = (x1 , . . . , xn )
x ← (); La ← {s}
solange La 6= ∅ :
Auswahl und Entfernen eines Knotens u aus La und Anhängen
an (das Ende von) x
La ← La \ {u}; x ← x ◦ (u)
Einfügen aller Kinder von u in La
201
Graphdurchquerungen – Spezifikation
Ziel: Besuch aller Knoten des Graphen G = (V , E)
Spezifikation Graphdurchquerung:
V: Eingabe Graph G = (V , E)
(und evtl. Startknoten s ∈ V )
N: Ausgabe Folge (x1 , . . . , xn ) (lineare DS) mit
1. {x1 , . . . , xn } = V
Jeder Knoten wird (wenigstens einmal) besucht.
2. ∀i, j ∈ {1, . . . , n} : i 6= j → xi 6= xj
Kein Knoten wird mehrmals besucht.
Spezialfall Bäume:
In den Baumdurchquerungsalgorithmen garantieren die
Baumeigenschaften die Erfüllung der Nachbedingungen:
Bäume sind
I
zusammenhängend (garantiert Nachbedingung 1.)
I
kreisfrei (garantiert Nachbedingung 2.)
202
Hilfsmengen für Graphdurchquerungen
Idee: Verallgemeinerung des allgemeinen Baum- zu einem
Graphdurchquerungsalgorithmus
Erweiterungen zur Garantie der Nachbedingungen notwendig:
Hilfsmenge Li zur Verwaltung der noch nicht entdeckten
(besuchten) Knoten des Graphen
zu Beginn Li = V , am Ende Li = ∅
(für Nachbed. 2.: kein Knoten mehrmals)
Neustart (für unzusammenhängende Graphen nötig)
falls La = ∅, aber noch nicht alle Knoten besucht,
Durchquerung bei beliebigem noch nicht
entdeckten Knoten neu beginnen
(für Nachbed. 1.: jeder Knoten wenigstens einmal)
Menge der Nachbarn eines Knotens u ∈ V in einem Graphen
G = (V , E):
N(u) = {v ∈ V | (u, v ) ∈ E}
203
Graph-Durchquerungs-Algorithmus
Erweiterung des (allgemeinen) Baum-Durchquerungs-Algorithmus:
Algorithmus : Graph-Durchquerung
Eingabe : G = (V , E) (und evtl. Startknoten s ∈ V )
Ausgabe : x = (x1 , . . . , xn )
x ← (); La ← {s}; Li ← V \ {s} (s Startknoten oder beliebig)
solange La 6= ∅ ∨ Li 6= ∅ :
Auswahl und Entfernen eines Knotens u aus La und Anhängen
an (das Ende von) x
La ← La \ {u}; x ← x ◦ (u)
Einfügen aller Nachbarn von u, die noch nicht entdeckt worden
(also noch in Li ) sind, in La :
La ← (N(u) ∩ Li ); Li ← Li \ N(u)
Neustart (nur bei unzusammenhängenden Graphen nötig)
Falls La = ∅ und Li 6= ∅:
Auswahl eines (beliebigen) Knoten v ∈ Li und
La ← {v }; Li ← Li \ {v }
204
Graph-Durchquerung
Invariante des Graph-Durchquerungs-Algorithmus:
Mengen La , Li , {xi | xi ∈ x} sind paarweise disjunkt
(Warum?)
Warum terminiert der Graph-Durchquerungs- Algorithmus?
anschauliche Darstellung durch verschiedene Färbung der
Knoten in Li , La und Menge der „erledigten“ Knoten und
schrittweise Umfärbung möglich
(oft auch Verwaltung der Umfärbungs-Zeitpunkte)
205
Datenstrukturen für Hilfmengen
auf Li benötigte Operationen:
Finden, Einfügen, Entfernen von Knoten
(beliebige Realisierung des ADT Menge)
auf La benötigte Operationen:
Auswahl (und Entfernen) des „nächsten“ Knotens,
Einfügen von Knoten (Nachbarn)
(Realisierung z.B. durch Stack, Queue, Priority-Queue)
Spezielle Graph-Durchquerungen analog Baumdurchquerungen
durch Datenstruktur zur Verwaltung von La :
Tiefensuche (DFS) bei Verwaltung von La als Stack
Breitensuche (BFS) bei Verwaltung von La als Queue
Beispiele (Tafel)
206
Wiederholung – Algorithmus von Dijkstra
(Dijkstra, 1959)
Ziel: Bestimmung kürzester Pfade von einem Knoten s eines
Graphen (mit Kantenmarkierung) zu allen von s erreichbaren Knoten
V: Eingabe: gewichteter Graph G = (V , E, l) mit l : V →
(positive Kantengewichte),
und Startknoten s ∈ V
R≥0
N: Ausgabe S = {(v , lv ) | v ∈ V } mit
∀v ∈ V : falls v von s erreichbar, ist (v , lv ) ∈ S und lv das
Minimum über die Länge (Summe der Markierungen) aller Pfade
von s nach v
(und evtl. ein kürzester Pfad von s nach v als Knotenfolge)
Idee: Graph-Durchquerungs-Algorithmus mit
I
Verwaltung von La als Priority-Queue
I
Priorität eines Knotens u:
Länge des kürzesten bisher bekannten Pfades von s nach u
I
falls zu einem Knoten (u, p) ∈ La ein Pfad mit Kosten p0 < p
gefunden wird,
Update der Priorität von u: La ← (La \ {(u, p)}) ∪ {(u, p0 )}
207
Gerüste eines Graphen
(Spannbäume, aufspannende Wälder)
Gerüst für einen Graphen G = (V , E):
maximaler kreisfreier Teilgraph G0 = (V , E 0 ) in G
Jedes Gerüst G0 = (V , E 0 ) in G definiert eine disjunkte
Zerlegung
{(V1 , ES1 ), . . . , (Vn , En )}
Sn
mit i=1 Vi = V , ni=1 Ei = E 0
(endliche Menge von Bäumen (Vi , Ei ))
Bestimmung von Gerüsten durch Graphdurchquerungen
Fakt
Jedes Gerüst für einen Graphen G enthält die gleiche Anzahl k
von Bäumen und es gilt |V | = |E| + k .
208
Gerüste und Zusammenhangskomponenten
Fakt
Die Zusammenhangskomponenten des Graphen G mit einem
Gerüst {(V1 , E1 ), . . . , (Vn , En )} sind genau die
von den Knotenmengen Vi induzierten Teilgraphen von G.
Durchquerung eines Graphen G =
Durchquerung aller Bäume eines Gerüstes G0 für G
209
Minimalgerüste
Minimalgerüst für einen Graphen G = (V , E, l) mit
Kantenmarkierungen l : E →
Gerüst G0 = (V , E 0 , l) für G mit minimaler Summe
aller Kantenmarkierungen,
d.h. für jedes Gerüst G00 = (V , E 00 , l) für G gilt
X
X
l(e) ≤
l(e)
R
e∈E 0
e∈E 00
Spezifikation Bestimmung eines Minimalgerüstes für G:
V: Eingabe Graph G = (V , E, l) mit Kantenmarkierung
l :E →
R
N: Ausgabe Minimalgerüst G0 für G
210
Algorithmus von Prim
(Jarnik 1930, Prim 1957)
Ziel: Bestimmung eines Minimalgerüstes eines Graphen
Eingabe: gewichteter Graph G = (V , E, l) (positive Gewichte)
Ausgabe: Minimalgerüst H = (V , E 0 ) für G
Idee: Graph-Durchquerungs-Algorithmus mit
I Verwaltung von La als Priority-Queue
I Priorität eines Knotens w: min{l(w, u) | u ∈ x}
Minimum über die Kosten aller Kanten von w zu einem
(schon erledigten) Knoten u ∈ x
I falls zu einem Knoten (u, p) ∈ La eine Kante (u, v ) mit
minimalem Abstand p0 < p zu einem Knoten v ∈ x
gefunden wird,
Update der Priorität: La ← (La \ {(u, p)}) ∪ {(u, p0 )}
I Verwaltung der Menge E 0 der ausgewählten Kanten
211
Herunterladen