Skip to content

Commit 95412ad

Browse files
authored
Create gabows_algorithm.py
Implemented Gabow's algorithm to find all the strongly connected components in a directed graph with a time complexity of O(V+E) as mentioned in the issue TheAlgorithms#12297
1 parent 6e24935 commit 95412ad

File tree

1 file changed

+113
-0
lines changed

1 file changed

+113
-0
lines changed

graphs/gabows_algorithm.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
"""
2+
This is a pure Python implementation of
3+
Gabow's algorithm for finding
4+
strongly connected components (SCCs)
5+
in a directed graph.
6+
7+
For doctests run:
8+
python -m doctest -v gabow_algorithm.py
9+
or
10+
python3 -m doctest -v gabow_algorithm.py
11+
For manual testing run:
12+
python gabow_algorithm.py
13+
"""
14+
15+
from collections import defaultdict
16+
from typing import List, Dict
17+
class Graph:
18+
"""
19+
Graph data structure to represent
20+
a directed graph and find SCCs
21+
using Gabow's algorithm.
22+
23+
Attributes:
24+
vertices (int): Number of
25+
vertices in the graph.
26+
graph (Dict[int, List[int]]):
27+
Adjacency list of the graph.
28+
29+
Methods:
30+
add_edge(u, v): Adds an edge
31+
from vertex u to vertex v.
32+
find_sccs(): Finds and returns
33+
all SCCs in the graph.
34+
35+
Examples:
36+
>>> g = Graph(5)
37+
>>> g.add_edge(0, 2)
38+
>>> g.add_edge(2, 1)
39+
>>> g.add_edge(1, 0)
40+
>>> g.add_edge(0, 3)
41+
>>> g.add_edge(3, 4)
42+
>>> sorted(g.find_sccs())
43+
[[0, 1, 2], [3], [4]]
44+
"""
45+
def __init__(self, vertices: int) -> None:
46+
self.vertices = vertices
47+
self.graph: Dict[int, List[int]] = defaultdict(list)
48+
self.index = 0
49+
self.stack_s = [] # Stack S
50+
self.stack_p = [] # Stack P
51+
self.visited = [False] * vertices
52+
self.result = []
53+
def add_edge(self, u: int, v: int) -> None:
54+
"""
55+
Adds a directed edge from vertex u to vertex v.
56+
57+
:param u: Starting vertex of the edge.
58+
:param v: Ending vertex of the edge.
59+
"""
60+
self.graph[u].append(v)
61+
62+
def _dfs(self, v: int) -> None:
63+
"""
64+
Depth-first search helper function to
65+
process each vertex and identify SCCs.
66+
:param v: The current vertex to process in DFS.
67+
"""
68+
self.visited[v] = True
69+
self.stack_s.append(v)
70+
self.stack_p.append(v)
71+
72+
for neighbor in self.graph[v]:
73+
if not self.visited[neighbor]:
74+
self._dfs(neighbor)
75+
elif neighbor in self.stack_p:
76+
while self.stack_p and self.stack_p[-1] != neighbor:
77+
self.stack_p.pop()
78+
if self.stack_p and self.stack_p[-1] == v:
79+
scc = []
80+
while True:
81+
node = self.stack_s.pop()
82+
scc.append(node)
83+
if node == v:
84+
break
85+
self.stack_p.pop()
86+
self.result.append(scc)
87+
def find_sccs(self) -> List[List[int]]:
88+
"""
89+
Finds all strongly connected components
90+
in the directed graph.
91+
:return: List of SCCs, where each SCC
92+
is represented as a list of vertices.
93+
"""
94+
for v in range(self.vertices):
95+
if not self.visited[v]:
96+
self._dfs(v)
97+
return self.result
98+
if __name__ == "__main__":
99+
import doctest
100+
doctest.testmod()
101+
# Example usage for manual testing
102+
try:
103+
vertex_count = int(input("Enter the number of vertices: "))
104+
g = Graph(vertex_count)
105+
edge_count = int(input("Enter the number of edges: "))
106+
print("Enter each edge as a pair of vertices (u v):")
107+
for _ in range(edge_count):
108+
u, v = map(int, input().split())
109+
g.add_edge(u, v)
110+
sccs = g.find_sccs()
111+
print("Strongly Connected Components:", sccs)
112+
except ValueError:
113+
print("Invalid input. Please enter valid integers.")

0 commit comments

Comments
 (0)