Skip to content

Commit 51492b7

Browse files
committed
Added Tarjan's algorithm for finding strongly connected components
1 parent 0d36dc6 commit 51492b7

File tree

1 file changed

+78
-0
lines changed

1 file changed

+78
-0
lines changed

Diff for: Graphs/tarjans_scc.py

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
from collections import deque
2+
3+
4+
def tarjan(g):
5+
"""
6+
Tarjan's algo for finding strongly connected components in a directed graph
7+
8+
Uses two main attributes of each node to track reachability, the index of that node within a component(index),
9+
and the lowest index reachable from that node(lowlink).
10+
11+
We then perform a dfs of the each component making sure to update these parameters for each node and saving the
12+
nodes we visit on the way.
13+
14+
If ever we find that the lowest reachable node from a current node is equal to the index of the current node then it
15+
must be the root of a strongly connected component and so we save it and it's equireachable vertices as a strongly
16+
connected component.
17+
18+
Complexity: strong_connect() is called at most once for each node and has a complexity of O(|E|) as it is DFS.
19+
Therefore this has complexity O(|V| + |E|) for a graph G = (V, E)
20+
21+
"""
22+
23+
n = len(g)
24+
stack = deque()
25+
on_stack = [False for _ in range(n)]
26+
index_of = [-1 for _ in range(n)]
27+
lowlink_of = index_of[:]
28+
29+
def strong_connect(v, index, components):
30+
index_of[v] = index # the number when this node is seen
31+
lowlink_of[v] = index # lowest rank node reachable from here
32+
index += 1
33+
stack.append(v)
34+
on_stack[v] = True
35+
36+
for w in g[v]:
37+
if index_of[w] == -1:
38+
index = strong_connect(w, index, components)
39+
lowlink_of[v] = lowlink_of[w] if lowlink_of[w] < lowlink_of[v] else lowlink_of[v]
40+
elif on_stack[w]:
41+
lowlink_of[v] = lowlink_of[w] if lowlink_of[w] < lowlink_of[v] else lowlink_of[v]
42+
43+
if lowlink_of[v] == index_of[v]:
44+
component = []
45+
w = stack.pop()
46+
on_stack[w] = False
47+
component.append(w)
48+
while w != v:
49+
w = stack.pop()
50+
on_stack[w] = False
51+
component.append(w)
52+
components.append(component)
53+
return index
54+
55+
components = []
56+
for v in range(n):
57+
if index_of[v] == -1:
58+
strong_connect(v, 0, components)
59+
60+
return components
61+
62+
63+
def create_graph(n, edges):
64+
g = [[] for _ in range(n)]
65+
for u, v in edges:
66+
g[u].append(v)
67+
return g
68+
69+
70+
if __name__ == '__main__':
71+
# Test
72+
n_vertices = 7
73+
source = [0, 0, 1, 2, 3, 3, 4, 4, 6]
74+
target = [1, 3, 2, 0, 1, 4, 5, 6, 5]
75+
edges = [(u, v) for u, v in zip(source, target)]
76+
g = create_graph(n_vertices, edges)
77+
78+
assert [[5], [6], [4], [3, 2, 1, 0]] == tarjan(g)

0 commit comments

Comments
 (0)