Skip to content

feat: Add Tarjan's strongly connected components algorithm #637

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions pydatastructs/graphs/algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,52 @@ def _strongly_connected_components_kosaraju_adjacency_list(graph):
_strongly_connected_components_kosaraju_adjacency_matrix = \
_strongly_connected_components_kosaraju_adjacency_list

def _tarjan_dfs(u, graph, index, stack, indices, low_links, on_stacks, components):
indices[u] = index[0]
low_links[u] = index[0]
index[0] += 1
stack.append(u)
on_stacks[u] = True

for node in graph.neighbors(u):
v = node.name
if indices[v] == -1:
_tarjan_dfs(v, graph, index, stack, indices, low_links, on_stacks, components)
low_links[u] = min(low_links[u], low_links[v])
elif on_stacks[v]:
low_links[u] = min(low_links[u], low_links[v])

if low_links[u] == indices[u]:
component = set()
while stack:
w = stack.pop()
on_stacks[w] = False
component.add(w)
if w == u:
break
components.append(component)

def _strongly_connected_components_tarjan_adjacency_list(graph):
index = [0] # mutable object
stack = Stack([])
indices, low_links, on_stacks = {}, {}, {}

for u in graph.vertices:
indices[u] = -1
low_links[u] = -1
on_stacks[u] = False

components = []

for u in graph.vertices:
if indices[u] == -1:
_tarjan_dfs(u, graph, index, stack, indices, low_links, on_stacks, components)

return components

_strongly_connected_components_tarjan_adjacency_matrix = \
_strongly_connected_components_tarjan_adjacency_list

def strongly_connected_components(graph, algorithm, **kwargs):
"""
Computes strongly connected components for the given
Expand All @@ -549,6 +595,7 @@ def strongly_connected_components(graph, algorithm, **kwargs):
supported,

'kosaraju' -> Kosaraju's algorithm as given in [1].
'tarjan' -> Tarjan's algorithm as given in [2].
backend: pydatastructs.Backend
The backend to be used.
Optional, by default, the best available
Expand Down Expand Up @@ -578,6 +625,7 @@ def strongly_connected_components(graph, algorithm, **kwargs):
==========

.. [1] https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm
.. [2] https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm

"""
raise_if_backend_is_not_python(
Expand Down
4 changes: 3 additions & 1 deletion pydatastructs/graphs/tests/test_algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,13 @@ def _test_strongly_connected_components(func, ds, algorithm, *args):
graph.add_edge(h.name, g.name)
comps = func(graph, algorithm)
expected_comps = [{'e', 'a', 'b'}, {'d', 'c', 'h'}, {'g', 'f'}]
assert comps == expected_comps
assert comps.sort() == expected_comps.sort()

scc = strongly_connected_components
_test_strongly_connected_components(scc, "List", "kosaraju")
_test_strongly_connected_components(scc, "Matrix", "kosaraju")
_test_strongly_connected_components(scc, "List", "tarjan")
_test_strongly_connected_components(scc, "Matrix", "tarjan")

def test_depth_first_search():

Expand Down
Loading