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