Skip to content

Commit

Permalink
Add Kosaraju algorithm (keon#910)
Browse files Browse the repository at this point in the history
* added kosaraju's algorithm under /algorithms/graph

* added test case for /algorithms/graph/strongly_connected_component_kosaraju

---------

Co-authored-by: Rubal Singh <[email protected]>
  • Loading branch information
rubalsxngh and Rubal Singh authored Feb 5, 2024
1 parent 40c944c commit e9c28af
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 0 deletions.
81 changes: 81 additions & 0 deletions algorithms/graph/strongly_connected_components_kosaraju.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"""
Implementing strongly connected components in a graph using Kosaraju's algorithm.
https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm
"""


class Kosaraju:
"""
Kosaraju's algorithm use depth first search approach to find strongly connected components in a directed graph.
Approach:
1. Make a DFS call to keep track of finish time of each vertex.
2. Tranpose the original graph. ie 1->2 transpose is 1<-2
3. Make another DFS call to calculate strongly connected components.
"""

def dfs(self, i, V, adj, visited, stk):
visited[i] = 1

for x in adj[i]:
if visited[x] == -1:
self.dfs(x, V, adj, visited, stk)

stk.append(i)

def kosaraju(self, V, adj):

stk, visited = [], [-1]*(V+1)

for i in range(V):
if visited[i] == -1:
self.dfs(i, V, adj, visited, stk)

stk.reverse()
res = stk.copy()

ans, visited1 = 0, [-1]*(V+1)

adj1 = [[] for x in range(V)]

for i in range(len(adj)):
for x in adj[i]:
adj1[x].append(i)

for i in range(len(res)):
if visited1[res[i]] == -1:
ans += 1
self.dfs(res[i], V, adj1, visited1, stk)

return ans


def main():
"""
Let's look at the sample input.
6 7 #no of vertex, no of edges
0 2 #directed edge 0->2
1 0
2 3
3 1
3 4
4 5
5 4
calculating no of strongly connected compnenets in a directed graph.
answer should be: 2
1st strong component: 0->2->3->1->0
2nd strongly connected component: 4->5->4
"""
V, E = map(int, input().split())
adj = [[] for x in range(V)]

for i in range(E):
u, v = map(int, input().split())
adj[u].append(v)

print(Kosaraju().kosaraju(V, adj))


if __name__ == '__main__':
main()
17 changes: 17 additions & 0 deletions tests/test_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from algorithms.graph import cycle_detection
from algorithms.graph import find_path
from algorithms.graph import path_between_two_vertices_in_digraph
from algorithms.graph import strongly_connected_components_kosaraju

import unittest

Expand Down Expand Up @@ -349,3 +350,19 @@ def test_node_is_reachable(self):
self.assertTrue(g.is_reachable(1, 3))
self.assertFalse(g.is_reachable(3, 1))

class TestStronglyConnectedComponentsKosaraju(unittest.TestCase):
def test_kosaraju_algorithm(self):
V = 6
adj = [
[2],
[0],
[3],
[1, 4],
[5],
[4]
]

result = strongly_connected_components_kosaraju.Kosaraju().kosaraju(V, adj)

# Expected result: 2 strongly connected components
self.assertEqual(result, 2)

0 comments on commit e9c28af

Please sign in to comment.