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:
-
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.
- Initialize an array
-
Initialize the Queue:
- Create a queue to hold all vertices with an in-degree of 0 (i.e., vertices that have no dependencies).
-
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 ).
- While the queue is not empty, perform the following:
-
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.