Algorithmen und Datenstrukturen

Werbung
Was bisher geschah
ADT Menge mit Operationen:
I
Suche nach einem Element
I
Einfügen eines Elementes
I
Löschen eines Elementes
Realisierung durch verschiedene Datenstrukturen:
I
lineare Datenstrukturen:
Array, Liste, Hashtabelle
I
hierarchische Datenstrukturen:
Suchbäume, balancierte Suchbäume
Datenstrukturen mit Zugriff nur auf ein spezielles Element:
Stack, Queue, Priority-Queue mit
1. Ansehen (top, first, getmin)
2. Entfernen (pop, dequeue, deletemin)
3. Einfügen einen Elementes (push, enqueue, add)
rekursive Baumdurchquerungen: pre-, post-, inorder
187
Nichtrekursive Baumdurchquerungen
(für Bäume beliebiger Knotengrade)
Zwischenspeicher notwendig zur Verwaltung der
Menge La der teilweise abgearbeiteten Knoten
Allgemeiner Durchquerungs-Algorithmus:
1. La = {s} (Wurzel s des zu durchquerenden Baumes)
2. solange La 6= ∅ wiederhole:
Auswahl und Entfernen eines Knotens u aus La
(u wird „verlassen“)
Einfügen aller Kinder von u in La
(Kinder von u werden „entdeckt“)
188
Nichtrekursive Baumdurchquerungen
Datenstruktur für Zwischenspeicher La (entdeckte, aber noch
nicht verlassene Knoten) bestimmt Durchquerungsreihenfolge.
Tiefensuche
Verwaltung von La als Stack
Einfügen der Nachbarn: push
I Auswahl des Knotens, der zuletzt in La
eingefügt wurde (pop)
(gleiche Reihenfolge wie preorder-Durchquerung)
I
I
Breitensuche
Verwaltung von La als Queue
Einfügen der Nachbarn: enqueue
I Auswahl des Knotens, der zuerst in La
eingefügt wurde (dequeue)
(level-order-Durchquerung)
I
I
189
Durchquerung von Bäumen mit Priority-Queue
allgemeiner Durchquerungs-Algorithmus:
1. La = {s} (Wurzel s des zu durchquerenden Baumes)
2. solange La 6= ∅ wiederhole:
Auswahl und Entfernen eines Knotens u aus La
Einfügen aller Kinder von u in La
Verwaltung von La als Stack: Tiefensuche
Verwaltung von La als Queue: Breitensuche
Verwaltung von La als Priority-Queue:
Auswahl des Knotens aus La : getmin (deletemin)
Einfügen der Kinder in La : add (mit geeigneten Prioritäten)
häufige Anwendung: Priorität = Bewertung der Knoten (Heuristik)
heuristische Suchverfahren, z.B. in Spielbäumen, Labyrinth-Suche
(mehr dazu in LV Wissensverarbeitung)
190
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)
191
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 )}
192
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
193
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.)
194
Hilfsmengen für Graphdurchquerungen
Idee: Verallgemeinerung des allgemeinen (nichtrekursiven)
Baum- zu einem Graphdurchquerungsalgorithmus
Erweiterungen zur Garantie der Nachbedingungen notwendig:
Hilfsmenge Li zur Verwaltung der noch nicht entdeckten
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}
195
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 }
196
Graph-Durchquerung
Invariante des Graph-Durchquerungs-Algorithmus:
Mengen La , Li , {xi | xi ∈ x} sind paarweise disjunkt
(Warum?)
Warum terminiert der Graph-Durchquerungs- Algorithmus?
häufig anzutreffende Variante:
Veranschaulichung durch verschiedene Färbung der Knoten in
Li , La und Menge der „erledigten“ Knoten und schrittweise
Umfärbung
(oft auch Verwaltung der Umfärbungs-Zeitpunkte)
197
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)
198
Graphen mit Kantenmarkierungen
Markierung der Kanten eines Graphen G = (V , E):
I Menge L von Kantenmarkierungen (häufig
, ,
I Markierungsfunktion l : E → L
Anwendungsbeispiele:
I Länge der Kante (z.B. Navigationssystem)
I Qualität der Kante (z.B. Autobahn, Feldweg)
I Preis der Kante (z.B. Fahrtkosten)
I Fassungsvermögen (Flussgraphen)
I (zeitweises) Sperren der Kanten
numerische Markierungen heißen oft Gewichte
N Z R≥0, R)
L-gewichteter Graph G = (V , E, l):
Graph (V , E) mit Markierungsfunktion l : E → L
(Gewichte aus L)
gewichteter Graph G = (V , E, l):
Graph (V , E) mit Markierungsfunktion l : E → L
(Gewichte aus beliebiger Menge L)
199
Kürzeste Wege in
R≥0-gewichteten Graphen
Aufgabe:
Bestimmung kürzester Pfade (und ihrer Länge) von einem
Knoten s eines ≥0 -gewichteten Graphen (positive
Kantengewichte) zu allen von s erreichbaren Knoten
R
V: gewichteter Graph G = (V , E, l) mit l : V →
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)
200
Algorithmus von Dijkstra
(Dijkstra, 1959)
Ziel: Bestimmung kürzester Pfade von einem Knoten s eines
≥0 -gewichteten Graphen zu allen von s erreichbaren Knoten
Idee: Graph-Durchquerungs-Algorithmus mit
R
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 (Summe des kürzesten bisher bekannten
Weges von s zum Vorgänger v von u und der Kante (v , u)
I
falls zu einem Knoten (u, p) ∈ La ein Pfad mit Kosten
p0 < p gefunden wird, Änderung (update)
der Priorität von u: La ← (La \ {(u, p)}) ∪ {(u, p0 )}
I
(evtl. Verwaltung des zu jedem Knoten ausgewählten
Pfades)
Achtung: nicht anwendbar bei negativen Gewichten
(dann stattdessen Algorithmus von Bellman und Ford)
201
Herunterladen