Skip to content

Create gabows_algorithm.py #12300

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

Closed
wants to merge 2 commits into from
Closed
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
121 changes: 121 additions & 0 deletions graphs/gabows_algorithm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
"""
This is a pure Python implementation of
Gabow's algorithm for finding
strongly connected components (SCCs)
in a directed graph.

For doctests run:
python -m doctest -v gabow_algorithm.py
or
python3 -m doctest -v gabow_algorithm.py
For manual testing run:
python gabow_algorithm.py
"""

from collections import defaultdict
from typing import List, Dict

Check failure on line 16 in graphs/gabows_algorithm.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (UP035)

graphs/gabows_algorithm.py:16:1: UP035 `typing.List` is deprecated, use `list` instead

Check failure on line 16 in graphs/gabows_algorithm.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (UP035)

graphs/gabows_algorithm.py:16:1: UP035 `typing.Dict` is deprecated, use `dict` instead


class Graph:

Check failure on line 19 in graphs/gabows_algorithm.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (I001)

graphs/gabows_algorithm.py:15:1: I001 Import block is un-sorted or un-formatted
"""
Graph data structure to represent
a directed graph and find SCCs
using Gabow's algorithm.

Attributes:
vertices (int): Number of
vertices in the graph.
graph (Dict[int, List[int]]):
Adjacency list of the graph.

Methods:
add_edge(u, v): Adds an edge
from vertex u to vertex v.
find_sccs(): Finds and returns
all SCCs in the graph.

Examples:
>>> g = Graph(5)
>>> g.add_edge(0, 2)
>>> g.add_edge(2, 1)
>>> g.add_edge(1, 0)
>>> g.add_edge(0, 3)
>>> g.add_edge(3, 4)
>>> sorted(g.find_sccs())
[[0, 1, 2], [3], [4]]
"""

def __init__(self, vertices: int) -> None:
self.vertices = vertices
self.graph: Dict[int, List[int]] = defaultdict(list)

Check failure on line 50 in graphs/gabows_algorithm.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (UP006)

graphs/gabows_algorithm.py:50:21: UP006 Use `dict` instead of `Dict` for type annotation

Check failure on line 50 in graphs/gabows_algorithm.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (UP006)

graphs/gabows_algorithm.py:50:31: UP006 Use `list` instead of `List` for type annotation
self.index = 0
self.stack_s = [] # Stack S
self.stack_p = [] # Stack P
self.visited = [False] * vertices
self.result = []

def add_edge(self, u: int, v: int) -> None:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide descriptive name for the parameter: u

Please provide descriptive name for the parameter: v

"""
Adds a directed edge from vertex u to vertex v.

:param u: Starting vertex of the edge.
:param v: Ending vertex of the edge.
"""
self.graph[u].append(v)

def _dfs(self, v: int) -> None:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide descriptive name for the parameter: v

"""
Depth-first search helper function to
process each vertex and identify SCCs.
:param v: The current vertex to process in DFS.
"""
self.visited[v] = True
self.stack_s.append(v)
self.stack_p.append(v)

for neighbor in self.graph[v]:
if not self.visited[neighbor]:
self._dfs(neighbor)
elif neighbor in self.stack_p:
while self.stack_p and self.stack_p[-1] != neighbor:
self.stack_p.pop()
if self.stack_p and self.stack_p[-1] == v:
scc = []
while True:
node = self.stack_s.pop()
scc.append(node)
if node == v:
break
self.stack_p.pop()
self.result.append(scc)

def find_sccs(self) -> List[List[int]]:

Check failure on line 92 in graphs/gabows_algorithm.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (UP006)

graphs/gabows_algorithm.py:92:28: UP006 Use `list` instead of `List` for type annotation

Check failure on line 92 in graphs/gabows_algorithm.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (UP006)

graphs/gabows_algorithm.py:92:33: UP006 Use `list` instead of `List` for type annotation
"""
Finds all strongly connected components
in the directed graph.
:return: List of SCCs, where each SCC
is represented as a list of vertices.
"""
for v in range(self.vertices):
if not self.visited[v]:
self._dfs(v)
return self.result


if __name__ == "__main__":
import doctest

doctest.testmod()
# Example usage for manual testing
try:
vertex_count = int(input("Enter the number of vertices: "))
g = Graph(vertex_count)
edge_count = int(input("Enter the number of edges: "))
print("Enter each edge as a pair of vertices (u v):")
for _ in range(edge_count):
u, v = map(int, input().split())
g.add_edge(u, v)
sccs = g.find_sccs()
print("Strongly Connected Components:", sccs)
except ValueError:
print("Invalid input. Please enter valid integers.")
Loading