Der Zusammenhang ist ein mathematischer Begriff aus der Graphentheorie. Ein Graph heißt zusammenhängend, wenn seine Knoten paarweise durch eine Kantenfolge verbunden sind.
Einen maximalen zusammenhängenden Teilgraphen eines Graphen nennt man eine Komponente oder Zusammenhangskomponente. Ein nicht zusammenhängender Graph wird durch seine Zusammenhangskomponenten partitioniert. Die größte Zusammenhangskomponente eines Graphen spielt im Erdős-Rényi-Modell eine wichtige Rolle.
Gerichtete Graphen
Ein gerichteter Graph heißt zusammenhängend von einem Knotenaus, falls es zu jedem Knoten aus einen gerichteten Weg in von nach gibt. heißt stark zusammenhängend, falls von jedem Knoten aus zusammenhängend ist. Anders formuliert heißt stark zusammenhängend, falls es zwischen zwei beliebigen Knoten und aus sowohl einen gerichteten Weg von nach als auch einen gerichteten Weg von nach in gibt.
Ein induzierter Teilgraph für eine Knotenmenge heißt starke Zusammenhangskomponente von , falls stark zusammenhängend ist und nicht zu einem größeren stark zusammenhängenden Teilgraphen von erweitert werden kann.
Ein gerichteter Graph heißt (schwach) zusammenhängend, falls der zugehörige ungerichtete Graph (also der Graph, der entsteht, wenn man jede gerichtete Kante durch eine ungerichtete Kante ersetzt) zusammenhängend ist.
Jeder stark zusammenhängende gerichtete Graph mit Knoten enthält mindestens Kanten.
Ein ungerichteter Graph ist genau dann zusammenhängend, wenn er einen Spannbaum enthält.
Ein gerichteter Graph ist genau dann stark zusammenhängend, wenn seine Adjazenzmatrixirreduzibel ist. Damit ist auch ein ungerichteter Graph genau dann zusammenhängend, wenn seine Adjazenzmatrix irreduzibel ist.
Die Klasse aller zusammenhängenden Graphen ist nicht axiomatisierbar.[1]
Mittels Tiefensuche lässt sich ein linearer Algorithmus implementieren, der die Zusammenhangskomponenten eines ungerichteten Graphen berechnet und somit auch testet, ob der Graph zusammenhängend ist. Der Test, ob ein gerichteter Graph von einem Knoten v aus zusammenhängend ist, funktioniert analog. Von Tarjan (1972) stammt ein linearer Algorithmus zum Bestimmen der starken Zusammenhangskomponenten in gerichteten Graphen. Leicht modifiziert findet dieser Algorithmus in ungerichteten Graphen die Blöcke und Artikulationen ebenfalls in linearer Zeit.[2]
Ein einfacher Algorithmus, der prüft, ob ein Graph zusammenhängend ist, kann wie folgt formuliert werden:
Beginne an einem beliebigen Knoten des Graphen.
Durchsuche von diesem Knoten aus entweder mit Tiefensuche oder mit Breitensuche den Graphen weiter, solange noch unbesuchte Nachbarknoten existieren.
Der Graph ist genau dann zusammenhängend, wenn am Ende die Anzahl der von der Suche erreichten Knoten gleich der Anzahl der Knoten des Graphen ist.
Anzahl der zusammenhängenden ungerichteten Graphen
n
mit nummerierten Knoten
ohne nummerierte Knoten
2
1
1
3
4
2
4
38
6
5
728
21
6
26704
112
7
1866256
853
8
251548592
11117
Programmierung
Das folgende Beispiel in der ProgrammierspracheC# zeigt die Implementierung eines ungerichteten Graphen mit Adjazenzlisten. Der ungerichtete Graph wird als KlasseUndirectedGraph deklariert. Bei der Ausführung des Programms wird die MethodeMain verwendet, die die Anzahl der Komponenten des Graphen auf der Konsole ausgibt.[5]
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;// Deklariert die Klasse für die Knoten des GraphenclassNode{publicintindex;publicstringvalue;publicHashSet<Node>adjacentNodes=newHashSet<Node>();// Menge der Nachbarknoten}// Deklariert die Klasse für den ungerichteten GraphenclassUndirectedGraph{publicHashSet<Node>nodes=newHashSet<Node>();// Diese Methode verbindet die Knoten node1 und node2 miteinander.publicvoidConnectNodes(Nodenode1,Nodenode2){node1.adjacentNodes.Add(node2);node2.adjacentNodes.Add(node1);}}classProgram{// Diese Methode gibt die Komponente des Graphen in der Form (A, B, C, ...) als Text zurück.publicstaticstringToString(HashSet<Node>nodes){stringtext="(";foreach(Nodenodeinnodes)// foreach-Schleife, die alle Knoten der Komponente durchläuft{text+=node.value+", ";}text=text.Substring(0,text.Length-2);text+=")";returntext;}// Hauptmethode, die das Programm ausführtpublicstaticvoidMain(string[]args){// Deklariert und initialisiert 5 KnotenNodenode1=newNode{index=0,value="A"};Nodenode2=newNode{index=1,value="B"};Nodenode3=newNode{index=2,value="C"};Nodenode4=newNode{index=3,value="D"};Nodenode5=newNode{index=4,value="E"};// Deklariert und initialisiert ein Array mit den KnotenNode[]nodes={node1,node2,node3,node4,node5};// Erzeugt einen ungerichteten GraphenUndirectedGraphundirectedGraph=newUndirectedGraph();intnumberOfNodes=nodes.Length;for(inti=0;i<numberOfNodes;i++)// for-Schleife, die alle Knoten durchläuft{undirectedGraph.nodes.Add(nodes[i]);// Fügt die Knoten dem Graphen hinzu}// Verbindet Knoten des Graphen miteinanderundirectedGraph.ConnectNodes(node1,node2);undirectedGraph.ConnectNodes(node3,node4);undirectedGraph.ConnectNodes(node4,node5);HashSet<Node>remainingNodes=newHashSet<Node>();// Menge der verbleibender Knoten, die noch nicht durchlaufen wurdenfor(inti=0;i<numberOfNodes;i++){remainingNodes.Add(nodes[i]);// Fügt die Knoten der Menge der verbleibender Knoten hinzu}intnumberOfComponents=1;HashSet<Node>newNodes=newHashSet<Node>();// Menge der neu durchlaufenen KnotennewNodes.Add(remainingNodes.ElementAt(0));// Dieser Menge einen neuen Knoten hinzufügenHashSet<Node>currentComponent=newHashSet<Node>();// Menge der Knoten für die aktuelle Komponentewhile(remainingNodes.Count>0)// So lange noch nicht alle Knoten durchlaufen wurden{HashSet<Node>currentNodes=newHashSet<Node>();// Menge für die aktuell durchlaufenen Knotenif(newNodes.Count==0)// Wenn keine neuen Knoten durchlaufen wurden{Console.WriteLine(ToString(currentComponent));// Gibt die Knoten der aktuellen Komponente auf der Konsole auscurrentComponent.Clear();numberOfComponents++;// Zähler für die Anzahl der Komponenten um 1 erhöhencurrentNodes.Add(remainingNodes.ElementAt(0));// Neuen Knoten durchlaufen}else{foreach(NodenodeinnewNodes)// foreach-Schleife, die alle neuen Knoten durchläuft{currentNodes.Add(node);// Fügt die neuen Knoten der Menge der aktuellen Knoten hinzu}}newNodes.Clear();// Leert die Menge der neu durchlaufenen Knotenforeach(NodenodeincurrentNodes)// foreach-Schleife, die alle aktuellen Knoten durchläuft{if(remainingNodes.Contains(node))// Wenn der aktuelle Knoten noch nicht durchlaufen wurde{currentComponent.Add(node);// Fügt den aktuellen Knoten der Menge der Knoten für die aktuellen Komponente hinzuremainingNodes.Remove(node);}foreach(NodenextNodeinnode.adjacentNodes)// foreach-Schleife, die alle benachbarten Knoten des aktuellen Knotens durchläuft{if(remainingNodes.Contains(nextNode)){currentComponent.Add(nextNode);// Fügt den benachbarten Knoten der Menge der Knoten für die aktuellen Komponente hinzunewNodes.Add(nextNode);// Fügt diesen Knoten der Menge der neu durchlaufenen KnotenremainingNodes.Remove(nextNode);}}}}Console.WriteLine(ToString(currentComponent));// Gibt die Knoten der aktuellen Komponente auf der Konsole ausConsole.WriteLine("Der Graph besteht aus "+numberOfComponents+" Komponenten.");// Ausgabe auf der KonsoleConsole.ReadLine();}}
Literatur
Lutz Volkmann: Fundamente der Graphentheorie. Springer, Wien 2001, ISBN 3-211-82774-9.