Zusammenhangskomponenten (Algorithmus 4.3)
Die Zusammenhangskomponenten aus Sedgewick/Wayne, Algorithmus 4.3 (Listing 4.8) – die for-Schleife des Konstruktors, je Komponente eine Tiefensuche, id[] und count Schritt für Schritt, dazu connected(v, w), am Graphen tinyG aus dem Buch.
So geht’s: Beim Öffnen läuft der Testclient mit dem Graphen tinyG aus dem Buch: erst entsteht der Graph Kante für Kante, dann arbeitet der Konstruktor. Seine for-Schleife geht die Knoten der Reihe nach durch (gestrichelt umrandet, Marke „s“). Trifft sie auf einen unmarkierten Knoten, startet dort eine Tiefensuche – Aufruf für Aufruf wie bei der Tiefensuche, orange der laufende Aufruf, orange umrandet die wartenden, blau der Nachbar, der gerade geprüft wird. Jeder erreichte Knoten bekommt id[v] = count und die Farbe seiner Komponente; ist die Suche fertig, zählt count++ weiter. „Bis fertig“ springt jeweils bis zum Ende einer Komponente. Am Ende sammelt der Testclient die Knoten in Bags und gibt sie aus – rückwärts, wie im Buch. Oben lässt sich mit connected(v, w) jede Frage stellen oder ein Zufallsgraph erzeugen, der meist in mehrere Teile zerfällt. „↺ Neu starten“ lädt den Testclient neu.
Erklärung
Zusammenhangskomponenten (Algorithmus 4.3), Klasse CC (connected components). Frage: In welche unabhängigen Teile zerfällt der Graph, und liegen zwei Knoten im selben Teil?
Der Code:
marked[]: besucht oder nicht.id[]: Nummer der Komponente für jeden Knoten.count: Anzahl der Komponenten bisher.- Konstruktor: Alle Knoten der Reihe nach durchgehen. Trifft man auf einen unmarkierten, startet man von dort eine Tiefensuche und zählt danach
counthoch. dfs(G, v): wie in [30], nur dass stattedgeTojetztid[v] = countgesetzt wird. Jeder Knoten, den diese Suche erreicht, bekommt die aktuelle Komponentennummer.connected(v, w):id[v] == id[w]. Genau wie bei Union-Find [19].
Das Beispiel tinyG.txt (13 Knoten, 13 Kanten):
- Tiefensuche ab 0 erreicht 0 bis 6 → alle bekommen id 0.
- Nächster unmarkierter ist 7 → erreicht 7 und 8 → id 1.
- Nächster unmarkierter ist 9 → erreicht 9 bis 12 → id 2.
- Ergebnis: 3 Komponenten.
- Die Ausgabe zeigt die Knoten jeder Komponente rückwärts (6 5 4 3 2 1 0), weil der Testclient sie in Bags [17] sammelt und
addimmer vorne einfügt.
Satz C: Vorverarbeitung in Zeit und Speicher proportional zu V + E. Danach beantwortet connected() jede Anfrage in konstanter Zeit.
CC vs. Union-Find [19], [21]: Beide lösen dasselbe Problem mit derselben id[]-Idee, aber in unterschiedlichen Situationen.
| CC (Tiefensuche, 4.3) | Union-Find (1.5) | |
|---|---|---|
| Voraussetzung | ganzer Graph liegt vor | Kanten kommen nacheinander rein |
| Vorverarbeitung | V + E | keine |
Anfrage connected | konstant | fast konstant (lg N bzw. mit Pfadkomprimierung praktisch konstant) |
| Neue Kante später | alles neu berechnen | einfach union |
| Pfad ausgeben | über DFS möglich | nicht möglich |
Faustregel aus dem Buch: Graph fest und viele Anfragen → CC. Graph wächst laufend → Union-Find. In der Praxis ist Union-Find oft schneller, weil kein vollständiger Graph aufgebaut werden muss.
Stand Kapitel 4: