Skip to main content

Kahn's Algorithm

πŸ“š Kahn's Algorithm​

Kahn's Algorithm is an efficient method for performing topological sorting on a Directed Acyclic Graph (DAG). It provides a way to order the vertices of the graph such that for every directed edge ( u \rightarrow v ), vertex ( u ) comes before vertex ( v ) in the ordering. This algorithm is particularly useful in scenarios where certain tasks must be completed before others, such as scheduling problems or resolving dependencies.

πŸ“ How Kahn's Algorithm Works​

Kahn's Algorithm operates based on the concept of in-degrees of vertices in a directed graph. The in-degree of a vertex is the number of edges directed towards it. The algorithm follows these steps:

  1. Calculate In-Degrees:

    • Initialize an array inDegree to keep track of the in-degrees of all vertices.
    • Traverse the graph and populate the inDegree array.
  2. Initialize the Queue:

    • Create a queue to hold all vertices with an in-degree of 0 (i.e., vertices that have no dependencies).
  3. Process the Queue:

    • While the queue is not empty, perform the following:
      • Dequeue a vertex ( u ) and append it to the topological ordering.
      • For each outgoing edge from ( u ) to vertex ( v ), reduce the in-degree of ( v ) by 1.
      • If the in-degree of ( v ) becomes 0, enqueue ( v ).
  4. Check for Cycles:

    • After processing all vertices, if the number of vertices in the topological ordering is less than the total number of vertices in the graph, a cycle exists, and a topological sort is not possible.

πŸ› οΈ Time Complexity​

The time complexity of Kahn's Algorithm is ( O(V + E) ), where ( V ) is the number of vertices and ( E ) is the number of edges in the graph. This efficiency makes Kahn's Algorithm suitable for large graphs.

πŸ–₯️ C++ Implementation​

Here’s how Kahn's Algorithm can be implemented in C++:

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

vector<int> kahnTopologicalSort(int V, vector<vector<int>>& adj) {
vector<int> inDegree(V, 0);
vector<int> topologicalOrder;

// Calculate in-degrees of all vertices
for (int u = 0; u < V; u++) {
for (int v : adj[u]) {
inDegree[v]++;
}
}

// Initialize the queue with vertices of in-degree 0
queue<int> q;
for (int i = 0; i < V; i++) {
if (inDegree[i] == 0) {
q.push(i);
}
}

// Process the queue
while (!q.empty()) {
int u = q.front();
q.pop();
topologicalOrder.push_back(u);

for (int v : adj[u]) {
inDegree[v]--;
if (inDegree[v] == 0) {
q.push(v);
}
}
}

// Check if there was a cycle
if (topologicalOrder.size() != V) {
return {}; // Return an empty vector if there's a cycle
}

return topologicalOrder; // Return the topological order
}

int main() {
int V = 6; // Number of vertices
vector<vector<int>> adj(V);

// Example graph edges (0->1, 0->2, etc.)
adj[5].push_back(2);
adj[5].push_back(0);
adj[4].push_back(0);
adj[4].push_back(1);
adj[2].push_back(3);
adj[3].push_back(1);

vector<int> result = kahnTopologicalSort(V, adj);

if (result.empty()) {
cout << "Graph has a cycle, topological sort not possible." << endl;
} else {
cout << "Topological Sort: ";
for (int u : result) {
cout << u << " ";
}
cout << endl;
}

return 0;
}


πŸ–₯️ Java Implementation​

Here’s how Kahn's Algorithm can be implemented in Java:


import java.util.*;

public class Main {

public static ArrayList<Integer> kahnTopologicalSort(int V, ArrayList<ArrayList<Integer>> adj) {

int[] inDegree = new int[V];
for(int i=0; i<V; i++)
{
for(int node : adj.get(i))
inDegree[node]++;
}

Queue<Integer> q = new LinkedList<>();
ArrayList<Integer> topologicalOrder = new ArrayList<>();

for(int i=0; i<V; i++)
{
if(inDegree[i] == 0)
{
q.offer(i);
topologicalOrder.add(i);
}
}

while(!q.isEmpty())
{
int node = q.poll();

for(int adjN : adj.get(node))
{
inDegree[adjN]--;
if(inDegree[adjN] == 0)
{
q.offer(adjN);
topologicalOrder.add(adjN);
}
}
}

if(topologicalOrder.size() != V)
return new ArrayList<Integer>();

return topologicalOrder;

}

public static void main(String args[]) {

int V = 6;
ArrayList<ArrayList<Integer>> adj = new ArrayList<>(V);

for(int i=0; i<V; i++)
adj.add(new ArrayList<>());

adj.get(5).add(2);
adj.get(5).add(0);
adj.get(4).add(0);
adj.get(4).add(1);
adj.get(2).add(3);
adj.get(3).add(1);
// adj.get(3).add(5); // add this node. it will create cycic graph

ArrayList<Integer> result = kahnTopologicalSort(V, adj);

if(result.size() == 0)
System.out.println("Graph has a cycle, topological sort not possible.");
else
{
System.out.println("Topological Sort: ");
for(int u : result)
System.out.print(u + " ");
}
}
}

Output​

Topological Sort:
4 5 2 0 3 1

πŸ” Applications of Kahn's Algorithm​

Task Scheduling: Used in scenarios where certain tasks must be completed before others. Build Systems: Helps manage dependencies between files and targets. Course Scheduling: Useful in academic settings to manage prerequisite courses. Version Control Systems: Resolves dependencies in source code versioning.

βš–οΈ Advantages and Limitations​

Advantages: Provides a clear and efficient method for topological sorting. Handles large graphs effectively with O(V+E) time complexity.

Limitations:​

Only applicable to Directed Acyclic Graphs (DAGs); Cannot be used for graphs with cycles.

πŸ“ Conclusion​

Kahn's Algorithm is a powerful tool for performing topological sorting in directed acyclic graphs. Its efficiency and straightforward implementation make it a preferred choice in many applications requiring task management based on dependencies. Understanding this algorithm can significantly aid in solving various computational problems involving directed graphs.