Comparison between Tarjan's and Kosaraju's Algorithm
Last Updated :
15 Jul, 2025
Tarjan's Algorithm: The Tarjan's Algorithm is an efficient graph algorithm that is used to find the Strongly Connected Component(SCC) in a directed graph by using only one DFS traversal in linear time complexity.
Working:
- Perform a DFS traversal over the nodes so that the sub-trees of the Strongly Connected Components are removed when they are encountered.
- Then two values are assigned:
- The first value is the counter value when the node is explored for the first time.
- Second value stores the lowest node value reachable from the initial node which is not part of another SCC.
- When the nodes are explored, they are pushed into a stack.
- If there are any unexplored children of a node are left, they are explored and the assigned value is respectively updated.
Below is the program to find the SCC of the given graph using Tarjan's Algorithm:
C++
// C++ program to find the SCC using
// Tarjan's algorithm (single DFS)
#include <iostream>
#include <list>
#include <stack>
#define NIL -1
using namespace std;
// A class that represents
// an directed graph
class Graph {
// No. of vertices
int V;
// A dynamic array of adjacency lists
list<int>* adj;
// A Recursive DFS based function
// used by SCC()
void SCCUtil(int u, int disc[],
int low[], stack<int>* st,
bool stackMember[]);
public:
// Member functions
Graph(int V);
void addEdge(int v, int w);
void SCC();
};
// Constructor
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V];
}
// Function to add an edge to the graph
void Graph::addEdge(int v, int w)
{
adj[v].push_back(w);
}
// Recursive function to finds the SCC
// using DFS traversal
void Graph::SCCUtil(int u, int disc[],
int low[], stack<int>* st,
bool stackMember[])
{
static int time = 0;
// Initialize discovery time
// and low value
disc[u] = low[u] = ++time;
st->push(u);
stackMember[u] = true;
// Go through all vertices
// adjacent to this
list<int>::iterator i;
for (i = adj[u].begin();
i != adj[u].end(); ++i) {
// v is current adjacent of 'u'
int v = *i;
// If v is not visited yet,
// then recur for it
if (disc[v] == -1) {
SCCUtil(v, disc, low,
st, stackMember);
// Check if the subtree rooted
// with 'v' has connection to
// one of the ancestors of 'u'
low[u] = min(low[u], low[v]);
}
// Update low value of 'u' only of
// 'v' is still in stack
else if (stackMember[v] == true)
low[u] = min(low[u], disc[v]);
}
// head node found, pop the stack
// and print an SCC
// Store stack extracted vertices
int w = 0;
// If low[u] and disc[u]
if (low[u] == disc[u]) {
// Until stack st is empty
while (st->top() != u) {
w = (int)st->top();
// Print the node
cout << w << " ";
stackMember[w] = false;
st->pop();
}
w = (int)st->top();
cout << w << "\n";
stackMember[w] = false;
st->pop();
}
}
// Function to find the SCC in the graph
void Graph::SCC()
{
// Stores the discovery times of
// the nodes
int* disc = new int[V];
// Stores the nodes with least
// discovery time
int* low = new int[V];
// Checks whether a node is in
// the stack or not
bool* stackMember = new bool[V];
// Stores all the connected ancestors
stack<int>* st = new stack<int>();
// Initialize disc and low,
// and stackMember arrays
for (int i = 0; i < V; i++) {
disc[i] = NIL;
low[i] = NIL;
stackMember[i] = false;
}
// Recursive helper function to
// find the SCC in DFS tree with
// vertex 'i'
for (int i = 0; i < V; i++) {
// If current node is not
// yet visited
if (disc[i] == NIL) {
SCCUtil(i, disc, low,
st, stackMember);
}
}
}
// Driver Code
int main()
{
// Given a graph
Graph g1(5);
g1.addEdge(1, 0);
g1.addEdge(0, 2);
g1.addEdge(2, 1);
g1.addEdge(0, 3);
g1.addEdge(3, 4);
// Function Call to find SCC using
// Tarjan's Algorithm
g1.SCC();
return 0;
}
Java
// java program to find the SCC using
// Tarjan's algorithm (single DFS)
import java.io.*;
import java.util.*;
// A class that represents
// an directed graph
class GFG {
// No. of vertices
private int V;
// A Dynamic array of adjacency lists
private LinkedList<Integer>[] adj;
private int time;
// Constructor
GFG(int V) {
this.V = V;
adj = new LinkedList[V];
for (int i = 0; i < V; i++) {
adj[i] = new LinkedList<>();
}
}
// Function to add an edge to the graph
void addEdge(int v, int w) {
adj[v].add(w);
}
// Recursive function to find the SCC
// using DFS traversal
void SCCUtil(int u, int[] disc, int[] low, Stack<Integer> st, boolean[] stackMember) {
// Initialize discovery time
// and low value
disc[u] = low[u] = ++time;
st.push(u);
stackMember[u] = true;
// Go through all vertices
// adjacent to this
for (int v : adj[u]) {
// If v is not visited yet
// then recur for it
if (disc[v] == -1) {
SCCUtil(v, disc, low, st, stackMember);
// Check if the subtree rooted
// with 'v' has a connection to
// one of the ancestors of 'u'
low[u] = Math.min(low[u], low[v]);
}
// Update low value of 'u' only of
// 'v' is still in stack
else if (stackMember[v]) {
low[u] = Math.min(low[u], disc[v]);
}
}
// Head node found, pop the stack
// and print an SCC
if (low[u] == disc[u]) {
int w;
// Until stack st is empty
do {
w = st.pop();
// Print the node
System.out.print(w + " ");
stackMember[w] = false;
} while (w != u);
System.out.println();
}
}
// Function to find the SCC in the graph
void SCC() {
// Stores the discovery times of
// the nodes
int[] disc = new int[V];
// Stores the nodes with the
// least discovery time
int[] low = new int[V];
// Checks whether a node is in
// the stack or not
boolean[] stackMember = new boolean[V];
// Stores all the connected ancestors
Stack<Integer> st = new Stack<>();
// Initialize disc and low
// and stackMember arrays
Arrays.fill(disc, -1);
Arrays.fill(low, -1);
Arrays.fill(stackMember, false);
// Recursive helper function to
// find the SCC in DFS tree with
// vertex 'i'
for (int i = 0; i < V; i++) {
// If the current node is not
// yet visited
if (disc[i] == -1) {
SCCUtil(i, disc, low, st, stackMember);
}
}
}
}
// Driver Code
public class Main {
public static void main(String[] args) {
// Given a graph
GFG g1 = new GFG(5);
g1.addEdge(1, 0);
g1.addEdge(0, 2);
g1.addEdge(2, 1);
g1.addEdge(0, 3);
g1.addEdge(3, 4);
// Function Call to find SCC using
// Tarjan's Algorithm
g1.SCC();
}
}
Python3
from collections import defaultdict
class Graph:
def __init__(self, vertices):
self.V = vertices
self.adj = defaultdict(list)
self.time = 0
def add_edge(self, u, v):
self.adj[u].append(v)
def SCCUtil(self, u, disc, low, stackMember, st):
disc[u] = self.time
low[u] = self.time
self.time += 1
stackMember[u] = True
st.append(u)
for v in self.adj[u]:
if disc[v] == -1:
self.SCCUtil(v, disc, low, stackMember, st)
low[u] = min(low[u], low[v])
elif stackMember[v]:
low[u] = min(low[u], disc[v])
w = -1 # To store stack extracted vertices
if low[u] == disc[u]:
while w != u:
w = st.pop()
print(w, end=' ')
stackMember[w] = False
print()
def SCC(self):
disc = [-1] * self.V
low = [-1] * self.V
stackMember = [False] * self.V
st = []
for i in range(self.V):
if disc[i] == -1:
self.SCCUtil(i, disc, low, stackMember, st)
g = Graph(5)
g.add_edge(1, 0)
g.add_edge(0, 2)
g.add_edge(2, 1)
g.add_edge(0, 3)
g.add_edge(3, 4)
g.SCC()
C#
using System;
using System.Collections.Generic;
class Graph
{
private int V;
private List<int>[] adj;
private int time;
public Graph(int vertices)
{
V = vertices;
adj = new List<int>[V];
for (int i = 0; i < V; i++)
{
adj[i] = new List<int>();
}
time = 0;
}
public void AddEdge(int v, int w)
{
adj[v].Add(w);
}
private void SCCUtil(int u, int[] disc, int[] low, Stack<int> st, bool[] stackMember)
{
disc[u] = low[u] = ++time;
st.Push(u);
stackMember[u] = true;
foreach (int v in adj[u])
{
if (disc[v] == -1)
{
SCCUtil(v, disc, low, st, stackMember);
low[u] = Math.Min(low[u], low[v]);
}
else if (stackMember[v])
{
low[u] = Math.Min(low[u], disc[v]);
}
}
if (low[u] == disc[u])
{
while (st.Count > 0)
{
int w = st.Pop();
stackMember[w] = false;
Console.Write(w);
if (w == u)
{
Console.WriteLine();
break;
}
else
{
Console.Write(" ");
}
}
}
}
public void SCC()
{
int[] disc = new int[V];
int[] low = new int[V];
bool[] stackMember = new bool[V];
Stack<int> st = new Stack<int>();
for (int i = 0; i < V; i++)
{
disc[i] = -1;
low[i] = -1;
stackMember[i] = false;
}
for (int i = 0; i < V; i++)
{
if (disc[i] == -1)
{
SCCUtil(i, disc, low, st, stackMember);
}
}
}
public static void Main(string[] args)
{
Graph g1 = new Graph(5);
g1.AddEdge(1, 0);
g1.AddEdge(0, 2);
g1.AddEdge(2, 1);
g1.AddEdge(0, 3);
g1.AddEdge(3, 4);
g1.SCC();
}
}
JavaScript
// javascript program to find the SCC using
// Tarjan's algorithm (single DFS)
let NIL = -1
let time = 0;
// A class that represents
// an directed graph
class Graph {
constructor(V){
// Number of vertices
this.V = V;
// Number of neighbours
this.adj = new Array(V);
for(let i = 0; i < V; i++){
this.adj[i] = new Array();
}
}
// Function to add an edge to the graph
addEdge(v, w)
{
this.adj[v].push(w);
}
// Recursive function to finds the SCC
// using DFS traversal
SCCUtil(u, disc, low, st, stackMember)
{
// Initialize discovery time
// and low value
disc[u] = low[u] = ++time;
st.push(u);
stackMember[u] = true;
// Go through all vertices
// adjacent to this
for (let i = 0; i < this.adj[u].length; i++){
// v is current adjacent of 'u'
let v = this.adj[u][i];
// If v is not visited yet,
// then recur for it
if (disc[v] == -1) {
this.SCCUtil(v, disc, low, st, stackMember);
// Check if the subtree rooted
// with 'v' has connection to
// one of the ancestors of 'u'
low[u] = Math.min(low[u], low[v]);
}
// Update low value of 'u' only of
// 'v' is still in stack
else if (stackMember[v] == true)
low[u] = Math.min(low[u], disc[v]);
}
// head node found, pop the stack
// and print an SCC
// Store stack extracted vertices
let w = 0;
// If low[u] and disc[u]
if (low[u] == disc[u]) {
// Until stack st is empty
while (st[st.length-1] != u) {
w = st[st.length-1];
// Print the node
process.stdout.write(w + " ");
stackMember[w] = false;
st.pop();
}
w = st[st.length-1];
process.stdout.write(w + "\n");
stackMember[w] = false;
st.pop();
}
}
// Function to find the SCC in the graph
SCC()
{
// Stores the discovery times of
// the nodes
let disc = new Array(this.V);
// Stores the nodes with least
// discovery time
let low = new Array(this.V);
// Checks whether a node is in
// the stack or not
let stackMember = new Array(this.V);
// Stores all the connected ancestors
let st = [];
// Initialize disc and low,
// and stackMember arrays
for (let i = 0; i < this.V; i++) {
disc[i] = NIL;
low[i] = NIL;
stackMember[i] = false;
}
// Recursive helper function to
// find the SCC in DFS tree with
// vertex 'i'
for (let i = 0; i < this.V; i++) {
// If current node is not
// yet visited
if (disc[i] == NIL) {
this.SCCUtil(i, disc, low, st, stackMember);
}
}
}
};
// Driver Code
// Given a graph
let g1 = new Graph(5);
g1.addEdge(1, 0);
g1.addEdge(0, 2);
g1.addEdge(2, 1);
g1.addEdge(0, 3);
g1.addEdge(3, 4);
// Function Call to find SCC using
// Tarjan's Algorithm
g1.SCC();
// The code is contributed by Nidhi goel.
Kosaraju's Algorithm: The Kosaraju's Algorithm is also a Depth First Search based algorithm which is used to find the SCC in a directed graph in linear time complexity. The basic concept of this algorithm is that if we are able to arrive at vertex v initially starting from vertex u, then we should be able to arrive at vertex u starting from vertex v, and if this is the situation, we can say and conclude that vertices u and v are strongly connected, and they are in the strongly connected sub-graph.
Working:
- Perform a DFS traversal on the given graph, keeping track of the finish times of each node. This process can be performed by using a stack.
- When the procedure of running the DFS traversal over the graph finishes, put the source vertex on the stack. In this way, the node with the highest finishing time will be at the top of the stack.
- Reverse the original graph by using an Adjacency List.
- Then perform another DFS traversal on the reversed graph with the source vertex as the vertex on the top of the stack. When the DFS running on the reversed graph finishes, all the nodes that are visited will form one strongly connected component.
- If any more nodes are left or remain unvisited, this signifies the presence of more than one strongly connected component on the graph.
- So pop the vertices from the top of the stack until a valid unvisited node is found. This will have the highest finishing time of all currently unvisited nodes.
Below is the program to find the SCC of the given graph using Kosaraju's Algorithm:
C++
// C++ program to print the SCC of the
// graph using Kosaraju's Algorithm
#include <iostream>
#include <list>
#include <stack>
using namespace std;
class Graph {
// No. of vertices
int V;
// An array of adjacency lists
list<int>* adj;
// Member Functions
void fillOrder(int v, bool visited[],
stack<int>& Stack);
void DFSUtil(int v, bool visited[]);
public:
Graph(int V);
void addEdge(int v, int w);
void printSCCs();
Graph getTranspose();
};
// Constructor of class
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V];
}
// Recursive function to print DFS
// starting from v
void Graph::DFSUtil(int v, bool visited[])
{
// Mark the current node as
// visited and print it
visited[v] = true;
cout << v << " ";
// Recur for all the vertices
// adjacent to this vertex
list<int>::iterator i;
// Traverse Adjacency List of node v
for (i = adj[v].begin();
i != adj[v].end(); ++i) {
// If child node *i is unvisited
if (!visited[*i])
DFSUtil(*i, visited);
}
}
// Function to get the transpose of
// the given graph
Graph Graph::getTranspose()
{
Graph g(V);
for (int v = 0; v < V; v++) {
// Recur for all the vertices
// adjacent to this vertex
list<int>::iterator i;
for (i = adj[v].begin();
i != adj[v].end(); ++i) {
// Add to adjacency list
g.adj[*i].push_back(v);
}
}
// Return the reversed graph
return g;
}
// Function to add an Edge to the given
// graph
void Graph::addEdge(int v, int w)
{
// Add w to v’s list
adj[v].push_back(w);
}
// Function that fills stack with vertices
// in increasing order of finishing times
void Graph::fillOrder(int v, bool visited[],
stack<int>& Stack)
{
// Mark the current node as
// visited and print it
visited[v] = true;
// Recur for all the vertices
// adjacent to this vertex
list<int>::iterator i;
for (i = adj[v].begin();
i != adj[v].end(); ++i) {
// If child node *i is unvisited
if (!visited[*i]) {
fillOrder(*i, visited, Stack);
}
}
// All vertices reachable from v
// are processed by now, push v
Stack.push(v);
}
// Function that finds and prints all
// strongly connected components
void Graph::printSCCs()
{
stack<int> Stack;
// Mark all the vertices as
// not visited (For first DFS)
bool* visited = new bool[V];
for (int i = 0; i < V; i++)
visited[i] = false;
// Fill vertices in stack according
// to their finishing times
for (int i = 0; i < V; i++)
if (visited[i] == false)
fillOrder(i, visited, Stack);
// Create a reversed graph
Graph gr = getTranspose();
// Mark all the vertices as not
// visited (For second DFS)
for (int i = 0; i < V; i++)
visited[i] = false;
// Now process all vertices in
// order defined by Stack
while (Stack.empty() == false) {
// Pop a vertex from stack
int v = Stack.top();
Stack.pop();
// Print SCC of the popped vertex
if (visited[v] == false) {
gr.DFSUtil(v, visited);
cout << endl;
}
}
}
// Driver Code
int main()
{
// Given Graph
Graph g(5);
g.addEdge(1, 0);
g.addEdge(0, 2);
g.addEdge(2, 1);
g.addEdge(0, 3);
g.addEdge(3, 4);
// Function Call to find the SCC
// using Kosaraju's Algorithm
g.printSCCs();
return 0;
}
Java
//Code in Java for the above approach
import java.util.*;
class Graph {
private int V; // Number of vertices in the graph
private LinkedList<Integer>[] adj; // Array of adjacency lists
Graph(int V) {
this.V = V;
adj = new LinkedList[V]; // Initialize adjacency lists for each vertex
for (int i = 0; i < V; i++) {
adj[i] = new LinkedList<>(); // Create a new linked list for each vertex
}
}
// Function to add an edge from vertex v to vertex w
void addEdge(int v, int w) {
adj[v].add(w); // Add w to the adjacency list of v
}
// Recursive utility function for Depth First Search (DFS)
void DFSUtil(int v, boolean[] visited) {
visited[v] = true; // Mark the current vertex as visited
System.out.print(v + " "); // Print the current vertex
// Iterate through adjacent vertices and perform DFS if not visited
for (Integer i : adj[v]) {
if (!visited[i]) {
DFSUtil(i, visited);
}
}
}
// Function to get the transpose (reverse) of the current graph
Graph getTranspose() {
Graph g = new Graph(V); // Create a new graph with the same number of vertices
for (int v = 0; v < V; v++) {
// Traverse the adjacency list of each vertex and add reverse edges
for (Integer i : adj[v]) {
g.adj[i].add(v); // Add edge from i to v in the new graph
}
}
return g; // Return the reversed graph
}
// Function to fill the stack with vertices in order of finishing times
void fillOrder(int v, boolean[] visited, Stack<Integer> stack) {
visited[v] = true; // Mark the current vertex as visited
// Iterate through adjacent vertices and perform DFS if not visited
for (Integer i : adj[v]) {
if (!visited[i]) {
fillOrder(i, visited, stack);
}
}
stack.push(v); // Push the vertex onto the stack after its DFS is complete
}
// Function to print strongly connected components using Kosaraju's Algorithm
void printSCCs() {
Stack<Integer> stack = new Stack<>(); // Stack to store vertices in order of finishing times
boolean[] visited = new boolean[V]; // Array to track visited vertices
// Fill the stack with vertices in order of finishing times
for (int i = 0; i < V; i++) {
if (!visited[i]) {
fillOrder(i, visited, stack);
}
}
Graph gr = getTranspose(); // Get the transpose (reverse) graph
Arrays.fill(visited, false); // Reset the visited array for the reversed graph
// Process vertices in the stack and print the strongly connected components
while (!stack.isEmpty()) {
int v = stack.pop(); // Pop a vertex from the stack
if (!visited[v]) {
gr.DFSUtil(v, visited); // Perform DFS on the reversed graph
System.out.println(); // Print a new line after each component
}
}
}
}
class Main {
public static void main(String[] args) {
Graph g = new Graph(5); // Create a graph with 5 vertices
g.addEdge(1, 0);
g.addEdge(0, 2);
g.addEdge(2, 1);
g.addEdge(0, 3);
g.addEdge(3, 4);
g.printSCCs(); // Print strongly connected components
}
}
Python3
# Python program to print the SCC of the
# graph using Kosaraju's Algorithm
# Class to represent a graph
class Graph:
def __init__(self,vertices):
self.V = vertices # No. of vertices
self.adj = [[] for i in range(vertices)] # adjacency list
# Function to add an edge to graph
def addEdge(self,u,v):
self.adj[u].append(v)
# A function used by DFS
def DFSUtil(self,v,visited):
# Mark the current node as visited
# and print it
visited[v] = True
print(v, end = ' ')
# Recur for all the vertices adjacent
# to this vertex
for i in self.adj[v]:
if visited[i] == False:
self.DFSUtil(i,visited)
# Function to get transpose of graph
def getTranspose(self):
g = Graph(self.V)
# Recur for all the vertices adjacent
# to this vertex
for v in range(self.V):
for i in self.adj[v]:
g.adj[i].append(v)
return g
# Function to fill vertices in stack
# in increasing order of finishing
# times
def fillOrder(self,v,visited,stack):
# Mark the current node as visited
visited[v] = True
# Recur for all the vertices adjacent
# to this vertex
for i in self.adj[v]:
if visited[i] == False:
self.fillOrder(i,visited,stack)
stack.append(v)
# Function to print all SCCs
def printSCCs(self):
# Create a stack to store vertices
stack = []
# Mark all the vertices as not visited
# (For first DFS)
visited = [False]*(self.V)
# Fill vertices in stack according to
# their finishing times
for i in range(self.V):
if visited[i] == False:
self.fillOrder(i,visited,stack)
# Create a reversed graph
gr = self.getTranspose()
# Mark all the vertices as not visited
# (For second DFS)
visited = [False]*(self.V)
# Now process all vertices in order
# defined by Stack
while stack:
i = stack.pop()
if visited[i] == False:
gr.DFSUtil(i,visited)
print()
# Driver Code
if __name__ == "__main__":
# Given graph
g = Graph(5)
g.addEdge(1, 0)
g.addEdge(0, 2)
g.addEdge(2, 1)
g.addEdge(0, 3)
g.addEdge(3, 4)
# Function Call to find the SCC
# using Kosaraju's Algorithm
g.printSCCs()
C#
using System;
using System.Collections.Generic;
using System.Linq;
class Graph
{
private int V; // Number of vertices in the graph
private List<int>[] adj; // Array of adjacency lists
public Graph(int V)
{
this.V = V;
adj = new List<int>[V]; // Initialize adjacency lists for each vertex
for (int i = 0; i < V; i++)
{
adj[i] = new List<int>(); // Create a new list for each vertex
}
}
// Function to add an edge from vertex v to vertex w
public void AddEdge(int v, int w)
{
adj[v].Add(w); // Add w to the adjacency list of v
}
// Recursive utility function for Depth First Search (DFS)
private void DFSUtil(int v, bool[] visited)
{
visited[v] = true; // Mark the current vertex as visited
Console.Write(v + " "); // Print the current vertex
// Iterate through adjacent vertices and perform DFS if not visited
foreach (int i in adj[v])
{
if (!visited[i])
{
DFSUtil(i, visited);
}
}
}
// Function to get the transpose (reverse) of the current graph
public Graph GetTranspose()
{
Graph g = new Graph(V); // Create a new graph with the same number of vertices
for (int v = 0; v < V; v++)
{
// Traverse the adjacency list of each vertex and add reverse edges
foreach (int i in adj[v])
{
g.adj[i].Add(v); // Add edge from i to v in the new graph
}
}
return g; // Return the reversed graph
}
// Function to fill the stack with vertices in order of finishing times
private void FillOrder(int v, bool[] visited, Stack<int> stack)
{
visited[v] = true; // Mark the current vertex as visited
// Iterate through adjacent vertices and perform DFS if not visited
foreach (int i in adj[v])
{
if (!visited[i])
{
FillOrder(i, visited, stack);
}
}
stack.Push(v); // Push the vertex onto the stack after its DFS is complete
}
// Function to print strongly connected components using Kosaraju's Algorithm
public void PrintSCCs()
{
Stack<int> stack = new Stack<int>(); // Stack to store vertices in order of finishing times
bool[] visited = new bool[V]; // Array to track visited vertices
// Fill the stack with vertices in order of finishing times
for (int i = 0; i < V; i++)
{
if (!visited[i])
{
FillOrder(i, visited, stack);
}
}
Graph gr = GetTranspose(); // Get the transpose (reverse) graph
Array.Fill(visited, false); // Reset the visited array for the reversed graph
// Process vertices in the stack and print the strongly connected components
while (stack.Count > 0)
{
int v = stack.Pop(); // Pop a vertex from the stack
if (!visited[v])
{
gr.DFSUtil(v, visited); // Perform DFS on the reversed graph
Console.WriteLine(); // Print a new line after each component
}
}
}
}
class Program
{
public static void Main()
{
Graph g = new Graph(5); // Create a graph with 5 vertices
g.AddEdge(1, 0);
g.AddEdge(0, 2);
g.AddEdge(2, 1);
g.AddEdge(0, 3);
g.AddEdge(3, 4);
g.PrintSCCs(); // Print strongly connected components
}
}
JavaScript
// Javascript code for the above approach
// Class to represent a graph
class Graph {
constructor(vertices) {
this.V = vertices; // No. of vertices
this.adj = new Array(vertices)
.fill()
.map(() => []); // adjacency list
}
// Function to add an edge to graph
addEdge(u, v) {
this.adj[u].push(v);
}
// A function used by DFS
DFSUtil(v, visited) {
// Mark the current node as visited
// and print it
visited[v] = true;
console.log(v);
// Recur for all the vertices adjacent
// to this vertex
for (let i of this.adj[v]) {
if (!visited[i]) {
this.DFSUtil(i, visited);
}
}
}
// Function to get transpose of graph
getTranspose() {
const g = new Graph(this.V);
// Recur for all the vertices adjacent
// to this vertex
for (let v = 0; v < this.V; v++) {
for (let i of this.adj[v]) {
g.adj[i].push(v);
}
}
return g;
}
// Function to fill vertices in stack
// in increasing order of finishing
// times
fillOrder(v, visited, stack) {
// Mark the current node as visited
visited[v] = true;
// Recur for all the vertices adjacent
// to this vertex
for (let i of this.adj[v]) {
if (!visited[i]) {
this.fillOrder(i, visited, stack);
}
}
stack.push(v);
}
// Function to print all SCCs
printSCCs() {
// Create a stack to store vertices
const stack = [];
// Mark all the vertices as not visited
// (For first DFS)
const visited = new Array(this.V).fill(false);
// Fill vertices in stack according to
// their finishing times
for (let i = 0; i < this.V; i++) {
if (!visited[i]) {
this.fillOrder(i, visited, stack);
}
}
// Create a reversed graph
const gr = this.getTranspose();
// Mark all the vertices as not visited
// (For second DFS)
visited.fill(false);
// Now process all vertices in order
// defined by Stack
while (stack.length > 0) {
const i = stack.pop();
if (!visited[i]) {
gr.DFSUtil(i, visited);
console.log('');
}
}
}
}
// Driver Code
// Given graph
const g = new Graph(5);
g.addEdge(1, 0);
g.addEdge(0, 2);
g.addEdge(2, 1);
g.addEdge(0, 3);
g.addEdge(3, 4);
// Function Call to find the SCC
// using Kosaraju's Algorithm
g.printSCCs();
// This code is contributed by sdeadityasharma
Time Complexity:
The time complexity of Tarjan's Algorithm and Kosaraju's Algorithm will be O(V + E), where V represents the set of vertices and E represents the set of edges of the graph. Tarjan's algorithm has much lower constant factors w.r.t Kosaraju's algorithm. In Kosaraju's algorithm, the traversal of the graph is done at least 2 times, so the constant factor can be of double time. We can print the SCC in progress with Kosaraju's algorithm as we perform the second DFS. While performing Tarjan's Algorithm, it requires extra time to print the SCC after finding the head of the SCCs sub-tree.
Summary:
Both the methods have the same linear time complexity, but the techniques or the procedure for the SCC computations are fairly different. Tarjan's method solely depends on the record of nodes in a DFS to partition the graph whereas Kosaraju's method performs the two DFS (or 3 DFS if we want to leave the original graph unchanged) on the graph and is quite similar to the method for finding the topological sorting of a graph.
Similar Reads
Basics & Prerequisites
Data Structures
Array Data StructureIn this article, we introduce array, implementation in different popular languages, its basic operations and commonly seen problems / interview questions. An array stores items (in case of C/C++ and Java Primitive Arrays) or their references (in case of Python, JS, Java Non-Primitive) at contiguous
3 min read
String in Data StructureA string is a sequence of characters. The following facts make string an interesting data structure.Small set of elements. Unlike normal array, strings typically have smaller set of items. For example, lowercase English alphabet has only 26 characters. ASCII has only 256 characters.Strings are immut
2 min read
Hashing in Data StructureHashing is a technique used in data structures that efficiently stores and retrieves data in a way that allows for quick access. Hashing involves mapping data to a specific index in a hash table (an array of items) using a hash function. It enables fast retrieval of information based on its key. The
2 min read
Linked List Data StructureA linked list is a fundamental data structure in computer science. It mainly allows efficient insertion and deletion operations compared to arrays. Like arrays, it is also used to implement other data structures like stack, queue and deque. Hereâs the comparison of Linked List vs Arrays Linked List:
2 min read
Stack Data StructureA Stack is a linear data structure that follows a particular order in which the operations are performed. The order may be LIFO(Last In First Out) or FILO(First In Last Out). LIFO implies that the element that is inserted last, comes out first and FILO implies that the element that is inserted first
2 min read
Queue Data StructureA Queue Data Structure is a fundamental concept in computer science used for storing and managing data in a specific order. It follows the principle of "First in, First out" (FIFO), where the first element added to the queue is the first one to be removed. It is used as a buffer in computer systems
2 min read
Tree Data StructureTree Data Structure is a non-linear data structure in which a collection of elements known as nodes are connected to each other via edges such that there exists exactly one path between any two nodes. Types of TreeBinary Tree : Every node has at most two childrenTernary Tree : Every node has at most
4 min read
Graph Data StructureGraph Data Structure is a collection of nodes connected by edges. It's used to represent relationships between different entities. If you are looking for topic-wise list of problems on different topics like DFS, BFS, Topological Sort, Shortest Path, etc., please refer to Graph Algorithms. Basics of
3 min read
Trie Data StructureThe Trie data structure is a tree-like structure used for storing a dynamic set of strings. It allows for efficient retrieval and storage of keys, making it highly effective in handling large datasets. Trie supports operations such as insertion, search, deletion of keys, and prefix searches. In this
15+ min read
Algorithms
Searching AlgorithmsSearching algorithms are essential tools in computer science used to locate specific items within a collection of data. In this tutorial, we are mainly going to focus upon searching in an array. When we search an item in an array, there are two most common algorithms used based on the type of input
2 min read
Sorting AlgorithmsA Sorting Algorithm is used to rearrange a given array or list of elements in an order. For example, a given array [10, 20, 5, 2] becomes [2, 5, 10, 20] after sorting in increasing order and becomes [20, 10, 5, 2] after sorting in decreasing order. There exist different sorting algorithms for differ
3 min read
Introduction to RecursionThe process in which a function calls itself directly or indirectly is called recursion and the corresponding function is called a recursive function. A recursive algorithm takes one step toward solution and then recursively call itself to further move. The algorithm stops once we reach the solution
14 min read
Greedy AlgorithmsGreedy algorithms are a class of algorithms that make locally optimal choices at each step with the hope of finding a global optimum solution. At every step of the algorithm, we make a choice that looks the best at the moment. To make the choice, we sometimes sort the array so that we can always get
3 min read
Graph AlgorithmsGraph is a non-linear data structure like tree data structure. The limitation of tree is, it can only represent hierarchical data. For situations where nodes or vertices are randomly connected with each other other, we use Graph. Example situations where we use graph data structure are, a social net
3 min read
Dynamic Programming or DPDynamic Programming is an algorithmic technique with the following properties.It is mainly an optimization over plain recursion. Wherever we see a recursive solution that has repeated calls for the same inputs, we can optimize it using Dynamic Programming. The idea is to simply store the results of
3 min read
Bitwise AlgorithmsBitwise algorithms in Data Structures and Algorithms (DSA) involve manipulating individual bits of binary representations of numbers to perform operations efficiently. These algorithms utilize bitwise operators like AND, OR, XOR, NOT, Left Shift, and Right Shift.BasicsIntroduction to Bitwise Algorit
4 min read
Advanced
Segment TreeSegment Tree is a data structure that allows efficient querying and updating of intervals or segments of an array. It is particularly useful for problems involving range queries, such as finding the sum, minimum, maximum, or any other operation over a specific range of elements in an array. The tree
3 min read
Pattern SearchingPattern searching algorithms are essential tools in computer science and data processing. These algorithms are designed to efficiently find a particular pattern within a larger set of data. Patten SearchingImportant Pattern Searching Algorithms:Naive String Matching : A Simple Algorithm that works i
2 min read
GeometryGeometry is a branch of mathematics that studies the properties, measurements, and relationships of points, lines, angles, surfaces, and solids. From basic lines and angles to complex structures, it helps us understand the world around us.Geometry for Students and BeginnersThis section covers key br
2 min read
Interview Preparation
Practice Problem