Terminologie
Graph: Ein Graph besteht aus einer Knotenmenge und einer Kantenmenge
- ungerichteter Graph: ein Graph ist ungerichtet, wenn jede in enthaltene Kante auch in der entgegengesetzten Richtung in enthalten ist
- gerichteter Graph: auch Digraph (directed graph)
- Graph mit Kantengewichten: Eine Funktion ordnet jeder Kante ein Gewicht zu
(Gerichteter) Pfad: Eine verbundene Folge von Kanten (bei gerichteten Graphen in entsprechender Richtung)
- Länge: Anzahl der Kanten auf dem Pfad
Zyklus / zyklischer Pfad: Ein Pfad, bei dem Startknoten und Endknoten identisch sind
Verbundenheit: Zwei Knoten sind verbunden, wenn zwischen ihnen ein Pfad existiert
Repräsentationen
Graphische Repräsentation: Gibt eine Intuition über die Struktur des Graphen
Kantenliste: schlicht jede Kante als Paar aus Knoten in einer verlinkten Liste speichern
Adjazensmatrix
Benutze eine Matrix adj mit vielen bool Einträgen
- für jede Kante zwischen Knoten und wird
adjwie folgt verändert:adj[v][w] = true(bei ungerichteten Graphen auchadj[w][v] = true) - für dünne Graphen mit brauchen wir trotzdem Speicher
Adjazenzlisten
Für jeden Knoten wir eine verlinkte Liste der Knoten gespeichert, zu denen der Knoten verbunden ist
- in der Praxis benutzt, weil Algorithmen oft über Nachbarknoten iterieren und echte Graphen meist dünn sind Kanten doppelt speichern ist akzeptabel
Graph mit Knotennamen
Zuordnung der Namen über Symboltabelle
- Knoten Name: Array
- Knoten im Graphen werden aufsteigend durchnummeriert
- Name Knoten: Links-neigender Rot-Schwarz-Baum
Kanten
Wir verwenden abstrakten Datentyp, der folgende Operationen unterstützt:
- either:
- other:
- from:
- to:
- weight:
Algorithmen auf Graphen
Zyklen finden
Wenn Tiefensuche von jedem Knoten aus keinen Zyklus hat, dann ist der Digraph zyklenfrei
- Topologische Sortierung möglich
Topologisches Sortieren
Auf einem azyklischen Digraphen (directed acyclic graph, DAG) ist eine topologische Ordnung eine Knotenordnung (Permutation), bei der alle gerichteten Kanten von einem in der Ordnung vorhergehenden zu einem in der Ordnung nachfolgenden Knoten zeigen.
Idee für Algorithmus: Tiefensuche laufen lassen und Knoten in umgekehrter Post-order-Reihenfolge zurückgeben
Satz: Die umgekehrte Post-order-Reihenfolge in einem azyklischen Digraphen ist eine topologische Sortierung.

Zusammenhangskomponente (ungerichteter Graph)
- Kantenrelation ist eine Äquivalenzrelation
- Eine Zusammenhangskomponente eines Graphen ist eine maximale Menge verbundener Knoten. Also eine Äquivalenzklasse.
- Zusammenhangskomponenten lassen sich über wiederholte Tiefensuche von jedem potentiellen Startknoten ermitteln
Starke Zusammenhangskomponente (gerichteter Graph)
Zwei Knoten in einem gerichteten Graphen sind stark zusammenhängend, wenn es jeweils einen Pfad in beide Richtungen gibt.
Die Relation starker Zusammenhänge (sconnected(v,w)) ist eine Äquivalenzrelation.
Starke Zusammenhangskomponente ist eine maximale Menge stark zusammenhängender Knoten.
Beispielanwendung:
- Interaktion von Software-Modulen
Kosaraju-Sharir-Algorithmus: Einfacher Algorithmus, um starke Zusammenhangskomponenten zu berechnen
- Phase 1: Tiefensuche auf inversem Digraph laufen lassen und Knoten in umgekehrter Post-order-Reihenfolge zurückgeben
- Phase 2: Tiefensuche auf (ursprünglichem) Digraphen laufen lassen mit Knotenreihenfolge aus Phase 1

Anmerkung: Bei der Tiefensuche werden hier Knoten mit hohem Index zuerst besucht 🤷♀️
Spannbäume
Ein Spannbaum eines ungerichteten Graphen ist ein Teilgraph von diesem, der
- zusammenhängend ist
- azyklisch ist
- alle Knoten umfasst
Ein Spannbaum ist also ein Baum, der alle Knoten umfasst. Daher hat der Spannbaum genau Kanten.
Minimale Spannbäume
In einem ungerichteten Graphen mit positiven Kantengewichten ist ein minimaler Spannbaum ein Spannbaum, bei dem die Summe der Kantengewichte minimal ist.
Anwendung: Netzwerkdesign (minimale Latenz / Abstände, maximale Vernetzung), Ethernet Bridges, Clustering-Algorithmen in KI
Schnitteigenschaft
Schnitt: Ein Schnitt teilt die Knotenmenge in einem Graphen in zwei nicht-leere, disjunkte Teilmengen
Kreuzende Kanten: Verbinden jeweils Knoten aus der einen Menge mit Knoten aus der anderen Menge.
Satz: Für jeden Schnitt liegt eine kreuzende Kante mit minimalem Gewicht im minimalen Spannbaum
Greedy-Algorithmus
- Färbe alle Kanten grau
- Finde einen Schnitt mit keiner schwarzen Kante
- Färbe die minimale kreuzende Kante schwarz
- Wiederhole bis Kanten schwarz
Prim’s Algorithmus
Idee: Baue den MST in einer Zusammenhangskomponente sukzessiv aus
- Beginne mit Knoten 0 im MST und füge alle seine Kanten in die Liste der kreuzenden Kanten ein
- Wähle die Kante in der Liste der kreuzenden Kanten, die minimales Gewicht hat
- Füge den neuen verbunden Knoten zum MST und füge alle seine Kanten zur Liste der kreuzenden Kanten hinzu
- Wiederhole Schritt 2 & 3 bis der MST Kanten hat oder keine Kante mehr in der Liste der kreuzenden Kanten liegt

Implementierung:
- Liste der Knoten im MST:
booleanArray (marked) - Liste der Kanten im MST:
Queue<Edge>Warteschlange - Liste der kreuzenden Kanten:
MinPQ<Edge>Prioritätswarteschlange (heap)
Aufwand:
- Speicher: , irgendwann alle Kanten in Prioritätswarteschlange
- Zeit: , für jede Kante einmal das Minimum in der Prioritätswarteschlange (heap) mit logarithmischer Laufzeit finden
Details:
- Lazy Prim: Entferne zyklische Kanten nicht während des Algorithmus
- Eager Prim: Entferne zyklische Kanten während des Algorithmus + Update aller minimalen Distanzen ist schneller
Gerichtete Graphen: Kürzeste Pfade bei positiven Kantengewichten
Anwendung:
- Routenplanung
- Bildbearbeitung (seam carving)
- Netzwerkrouting
Kürzeste-Pfade-Baum (SPT)
In einem Graphen mit einem frei gewählten Startknoten ist der Kürzeste-Pfade-Baum derjenige azyklische Teilgraph des Graphen, der als Wurzel und für alle von aus erreichbaren Knoten jeweils den kürzesten Pfad dorthin enthält
- Verallgemeinerung des MST auf gewichtete gerichtete Graphen
Kantenrelaxation
Idee: Betrachte Kante von nach . Überprüfe, ob der Pfad über diese Kante kürzer ist als der bisher kürzeste bekannte Pfad von nach .
void relax(const Edge& e) {
const int v = e.from();
const int w = e.to();
if (dist_to[w] > dist_to[v] + e.weight()) {
dist_to[w] = dist_to[v] + e.weight();
edge_to[w] = e;
}
}Dijkstras-Algorithmus
Idee: Baue den SPT sukkzesiv über die Knoten auf, die am nähesten am Startknoten sind
- Initialisieren alle Distanzen mit (außer dem Starknoten mit Distanz ) und färbe alle Knoten grau
- Beginne mit Knoten im SPT
- Färbe den momentanten Knoten weiß und relaxiere alle Nachbarkanten
- Wähle die Kante, die zum Knoten zeigt, der am nähesten an ist
- Wiederhole Schritt 3 & 4 bis alle Knoten weiß gefärbt sind
Implementierung:
- Prioritätswarteschlange über Kanten
- Prioritäten werden separat in einem Schlüssel gesetzt und müssen angepasst werden können
Dijkstras-Algorithmus und Prim’s Algorithmus sind essenziell gleich:
- beide berechnen einen minimalen Spannbaum
- Prim: Nähsten Knoten zum minimalen Spannbaum wählen
- Dijkstra: Nähsten Knoten zum Start wählen
Komplexität