|
| 1 | +# Tarjan's Algorithm |
| 2 | + |
| 3 | +Tarjan's Algorithm is an efficient method for finding all Strongly Connected Components (SCCs) in a directed graph. An SCC is a maximal subgraph where each vertex is reachable from every other vertex in the subgraph. |
| 4 | + |
| 5 | +## Algorithm Description |
| 6 | + |
| 7 | +Tarjan's Algorithm uses Depth-First Search (DFS) to identify SCCs in a graph. It maintains a stack to keep track of the vertices in the current path and uses two arrays (or dictionaries) to store the discovery times and the lowest points reachable for each vertex. |
| 8 | + |
| 9 | +## Steps |
| 10 | + |
| 11 | +1. Perform a DFS traversal of the graph. |
| 12 | +2. For each vertex, track the discovery time and the lowest discovery time reachable from that vertex. |
| 13 | +3. Use a stack to keep vertices of the current DFS path. |
| 14 | +4. When a vertex completes its DFS, check if it's the root of an SCC. If so, pop vertices from the stack to form the SCC. |
| 15 | +5. Continue until all vertices have been processed. |
| 16 | + |
| 17 | +## Time Complexity |
| 18 | + |
| 19 | +The time complexity of Tarjan's Algorithm is O(V + E), where V is the number of vertices and E is the number of edges in the graph. |
| 20 | + |
| 21 | +## Python Implementation |
| 22 | + |
| 23 | +Here is a Python implementation of Tarjan's Algorithm: |
| 24 | + |
| 25 | +```python |
| 26 | +from collections import defaultdict |
| 27 | + |
| 28 | +class TarjanSCC: |
| 29 | + def __init__(self, graph): |
| 30 | + self.graph = graph |
| 31 | + self.V = len(graph) |
| 32 | + self.index = 0 |
| 33 | + self.stack = [] |
| 34 | + self.in_stack = [False] * self.V |
| 35 | + self.indices = [-1] * self.V |
| 36 | + self.low_links = [-1] * self.V |
| 37 | + self.sccs = [] |
| 38 | + |
| 39 | + def find_sccs(self): |
| 40 | + for v in range(self.V): |
| 41 | + if self.indices[v] == -1: |
| 42 | + self._strong_connect(v) |
| 43 | + return self.sccs |
| 44 | + |
| 45 | + def _strong_connect(self, v): |
| 46 | + self.indices[v] = self.index |
| 47 | + self.low_links[v] = self.index |
| 48 | + self.index += 1 |
| 49 | + self.stack.append(v) |
| 50 | + self.in_stack[v] = True |
| 51 | + |
| 52 | + for w in self.graph[v]: |
| 53 | + if self.indices[w] == -1: |
| 54 | + self._strong_connect(w) |
| 55 | + self.low_links[v] = min(self.low_links[v], self.low_links[w]) |
| 56 | + elif self.in_stack[w]: |
| 57 | + self.low_links[v] = min(self.low_links[v], self.indices[w]) |
| 58 | + |
| 59 | + if self.low_links[v] == self.indices[v]: |
| 60 | + scc = [] |
| 61 | + while True: |
| 62 | + w = self.stack.pop() |
| 63 | + self.in_stack[w] = False |
| 64 | + scc.append(w) |
| 65 | + if w == v: |
| 66 | + break |
| 67 | + self.sccs.append(scc) |
| 68 | +``` |
| 69 | +# Example usage |
| 70 | +if __name__ == "__main__": |
| 71 | + # Define the graph as an adjacency list |
| 72 | + graph = defaultdict(list) |
| 73 | + graph[0].extend([1]) |
| 74 | + graph[1].extend([2]) |
| 75 | + graph[2].extend([0, 3]) |
| 76 | + graph[3].extend([4]) |
| 77 | + graph[4].extend([5, 7]) |
| 78 | + graph[5].extend([6]) |
| 79 | + graph[6].extend([4]) |
| 80 | + graph[7].extend([8]) |
| 81 | + graph[8].extend([7]) |
| 82 | + |
| 83 | + # Find SCCs |
| 84 | + tarjan = TarjanSCC(graph) |
| 85 | + sccs = tarjan.find_sccs() |
| 86 | + |
| 87 | + # Print the SCCs |
| 88 | + print("Strongly Connected Components:") |
| 89 | + for scc in sccs: |
| 90 | + print(scc) |
| 91 | + |
| 92 | +## Explanation |
| 93 | +The TarjanSCC class initializes the graph and necessary variables. |
| 94 | +The find_sccs method starts the DFS traversal and returns the list of SCCs. |
| 95 | +The _strong_connect method performs the DFS, updates discovery times and low links, and identifies SCCs. |
| 96 | +The example usage demonstrates how to define a graph, find SCCs using Tarjan's Algorithm, and print the results |
| 97 | + |
| 98 | +## Conclusion |
| 99 | +Tarjan's Algorithm is an efficient and elegant solution for finding all SCCs in a directed graph. Its linear time complexity makes it suitable for large graphs, and it is widely used in applications like compiler optimization, social network analysis, and more. |
| 100 | + |
0 commit comments