Kosaraju's algorithm
iterative DFS
finishing time
graph theory
algorithm analysis

kosaraju finding finishing time using iterative dfs

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Kosaraju's algorithm is an efficient method used to find the strongly connected components (SCCs) within a directed graph. An essential part of this algorithm is determining the finishing times of nodes, which helps in correctly ordering the processing of nodes. This article explores how to find these finishing times using an iterative depth-first search (DFS) approach. The iterative method offers several advantages, particularly regarding stack overflow issues in languages with limited stack sizes.

Understanding the Depth-First Search (DFS)

DFS is a fundamental graph traversal technique often used in graph algorithms. In DFS, traversal is conducted by exploring as far as possible along each branch before backtracking. This exploration can be performed either recursively or iteratively. While recursive implementations are straightforward, they can lead to stack overflow errors on deeply nested graphs. An iterative approach, on the other hand, utilizes an explicit stack data structure, helping to circumvent these issues.

Kosaraju's Algorithm Overview

Kosaraju's algorithm runs in two major passes:

  1. First Pass: Run DFS on the original graph to calculate finishing times.
  2. Second Pass: Run DFS on the transpose of the graph in the order of decreasing finishing times to discover SCCs.

Importance of Finishing Times

The finishing time in DFS denotes the step count when all vertices reachable from a given vertex, including the vertex itself, are completely explored. Obtaining correct finishing times is crucial for the successful execution of the second pass in Kosaraju's algorithm.

Iterative DFS to Determine Finishing Times

Data Structures

  1. Graph Representation: An adjacency list is typically employed for graph representation due to its space efficiency.
  2. Stack: Utilized to replace the call stack in recursive DFS implementations.
  3. Visited Array: Tracks whether a vertex is visited or not.
  4. Finish Stack: Stores the nodes in the order they complete processing, essentially capturing their finishing times.

Algorithm Steps

  1. Initialization:
    • Initialize an empty visited array to keep track of visited nodes.
    • Create an empty finish_stack.
  2. Iterative DFS Implementation:
    • For each node, if it hasn’t been visited, perform the following:
      • Push the node onto the stack.
      • While the stack is not empty:
        • Peek at the node on top of the stack.
        • If the node is not visited, mark it as visited.
        • Explore each of the node’s neighbors:
          • If a neighbor hasn't been visited, push it on the stack.
        • If all neighbors are visited:
          • Pop the node from the stack.
          • Push it to the finish_stack.
  3. Result:
    • The finish_stack will contain nodes sorted by finishing time, with the node having the highest finishing time at the top.

Python Code Example

python
1def iterative_dfs(graph):
2    visited = [False] * len(graph)
3    finish_stack = []
4    stack = []
5    
6    def dfs_at_vertex(v):
7        stack.append(v)
8        while stack:
9            node = stack[-1]
10            if not visited[node]:
11                visited[node] = True
12                for neighbor in graph[node]:
13                    if not visited[neighbor]:
14                        stack.append(neighbor)
15            else:
16                stack.pop()
17                if node not in finish_stack:
18                    finish_stack.append(node)
19
20    for i in range(len(graph)):
21        if not visited[i]:
22            dfs_at_vertex(i)
23
24    return finish_stack

Visualizing iterative DFS

Imagine the following directed graph for clarity:

 
10 --> 1 --> 2
2^     |
3| ------------------- | ----------------------------------------------------------------------------- |
4| Algorithm Focus | Finding finishing times using iterative DFS in Kosaraju’s algorithm |
5| Key Data Structures | Adjacency list, stack, visited array, finish stack |
6| Iterative Advantage | Mitigates recursion depth limitations & stack overflow risk |
7| Primary Output | Finishing times of nodes stored in finish stack |
8| Application Context | Essential for correctly ordering nodes in the second pass on transposed graph |
9
10### Concluding Remarks
11
12The use of iterative DFS in computing finishing times in Kosaraju's algorithm highlights the importance of algorithmic frameworks that remain robust beyond theoretical contexts. By employing explicit stack structures, developers can handle vast and intricate data structures without running afoul of system constraints, ensuring broader applicability and efficiency.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.