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
inDegreeto keep track of the in-degrees of all vertices. - Traverse the graph and populate the
inDegreearray.
- 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.
Completed working through this block? Sync progress to workspace.