Source code for algorithms.graphs.strongly_connected
"""
In the mathematical theory of directed graphs, a graph is said to be strongly connected or diconnected if every
vertex is reachable from every other vertex.
"""
import sys
from algorithms.graphs import reverse_graph, get_nodes
sys.setrecursionlimit(200000)
[docs]class StronglyConnected:
def __init__(self, graph):
self._reached = set()
self._visited = set()
self._stack = []
self.graph = graph
self._components = []
def _explore(self, node):
"""
Heler function - marks explored adjacent nodes in graph as reached and adds them on stack
Args:
node: node to check neighbourhoods
"""
self._components.append(node)
self._visited.add(node)
for adj in self.graph[node]:
if adj not in self._reached and adj not in self._visited:
self._explore(adj)
self._reached.add(node)
self._visited.remove(node)
self._stack.append(node)
def _dfs(self, graph):
"""
Helper function - classical DFS algorithm fro graph traversal
Args:
graph: graph representation
"""
nodes = get_nodes(graph)
for node in nodes:
if node not in self._reached:
self._explore(node)
[docs] def strongly_connected_components(self):
"""
Function finds, and return list of SCC in the graph
Returns:
list: SCC
Examples:
>>> graph = prepare_direct_graph([(0, 2), (2, 1), (1, 0), (0, 3), (3, 4)])
>>> StronglyConnected(graph).strongly_connected_components()
[[0, 1, 2], [3], [4]]
"""
scc = []
rev_graph = reverse_graph(self.graph)
self._dfs(rev_graph)
self._reached = set()
self.graph = rev_graph
while self._stack:
node = self._stack.pop()
if node not in self._reached:
self._components = []
self._explore(node)
scc.append(self._components)
return scc