I wrote a code to calculate the lengths of strongly connected components in a graph. The results I get are correct but it scales horribly.
This is the code I have. I understand that the runtime complexity of a graph traversals should be O(V+E)
and as far as I understand, I am not visiting any node twice. And yet it takes forever for bigger graphs (875714 nodes and 5105043 edges)
class Graph:
def __init__(self):
self.graph = {}
self.rev_graph = {}
self.num_vertices = 0
def addEdge(self, tail, head):
if tail in self.graph:
self.graph[tail].append(head)
else:
self.graph[tail]=[head]
if head in self.rev_graph:
self.rev_graph[head].append(tail)
else:
self.rev_graph[head] = [tail]
def dfs(self, visited, start_node, stack):
visited[start_node] = True
if start_node in self.graph:
for i in self.graph[start_node]:
if not visited[i]:
self.dfs(visited, i, stack)
# del self.rev_graph[start_node]
stack.append(start_node)
def dfs_counter(self, visited, start_node, delim=' '):
l1 = sum(visited)
visited[start_node] = True
if start_node in self.rev_graph:
# print(delim, 'rev graph neighbors: ', start_node, self.rev_graph[start_node])
for i in self.rev_graph[start_node]:
if not visited[i]:
self.dfs_counter(visited, i, 2*delim)
l2 = sum(visited)
return l2 - l1
# print(stack)
def find_scc_lens(self):
self.num_vertices = len(set(list(self.graph.keys()) + list(self.rev_graph.keys())))
visited = [False]*self.num_vertices
stack = []
self.dfs(visited, 0, stack)
# stack = stack[::-1]
# print(stack)
# del(self.graph)
visited = [False] * self.num_vertices
scc_lengths = []
for k,i in enumerate(stack[::-1]):
if not visited[i]:
# print("rev graph node count", k, i)
scc_lengths.append(self.dfs_counter(visited, i))
return scc_lengths
This exercise is from an online course I am taking. I tried a few other solutions online I found elsewhere and they are really fast compared to my runtimes.
What parts of the code can I optimize to improve the runtimes?
Example:
g = Graph()
g.addEdge(1, 0);
g.addEdge(0, 2);
g.addEdge(2, 1);
g.addEdge(0, 3);
g.addEdge(3, 4);
g.find_scc_lens()