AlgoDocs

Kahn's Algorithm

Kahn's algorithm is used to find a topological ordering of a directed acyclic graph (DAG).

Introduction

Kahn's Algorithm is a Breadth-First Search (BFS) based approach used to find a Topological Order of a Directed Acyclic Graph (DAG). Topological sorting of a DAG is a linear ordering of its vertices such that for every directed edge (u → v), vertex u appears before vertex v in the ordering.

How Kahn's Algorithm Works?

Compute the indegree of each node.

  • Traverse the graph and count incoming edges for each node.

Initialize a Queue with Nodes Having Zero In-Degree.

  • Create a queue and enqueue all nodes with an in-degree of zero.

Process the Nodes Using BFS

  • Remove a node from the queue and add it to the topological order.
  • Decrement the in-degree of its neighbor nodes.
  • If any node's in-degree becomes zero, add it to the queue.

Termination

  • If all nodes are included in the result, a valid topological ordering exists.
  • If not, the graph contains a cycle, meaning topological sorting is not possible.

Indegree

Indegree of node in directed graph is the number of incoming edges to that node.

Example

Visualization of Indegree

Carousel image 1
Carousel image 2
Carousel image 3
Carousel image 4
Carousel image 5
Carousel image 6
Carousel image 7
Carousel image 8

Implementation of Kahn's Algorithm

//kahn's.cpp
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
void kahns(vector<vector<int>>&adjlist,vector<int> &indegree){
queue<int> q;
for(int i=0;i<indegree.size();i++){
    if(indegree[i]==0){
        q.push(i);
    }
}
while(!q.empty()){
    int node=q.front();
    q.pop();
    cout<<node<<" ";
    for(int &v:adjlist[node]){
        indegree[v]--;
        if(indegree[v]==0){
            q.push(v);
        }
    }
}
}
int main()
{
int vertex, edge;
cin >> vertex >> edge;
vector<vector<int>> adjlist(vertex);
int u, v;
for (int i = 0; i < edge; i++)
{
    cin >> u >> v;
    adjlist[u].push_back(v);
}
vector<int> indegree(vertex);
for(int i=0;i<vertex;i++){
    for(int &v:adjlist[i]){
        indegree[v]++;
    }
}
kahns(adjlist,indegree);
}
# kahns_algorithm.py
from collections import deque

def kahns_algorithm(adj_list, num_vertices):
 """
 Kahn's algorithm for topological sorting using BFS approach
 """
 # Calculate indegree for each vertex
 indegree = [0] * num_vertices
 for u in range(num_vertices):
     for v in adj_list[u]:
         indegree[v] += 1
 
 # Initialize queue with vertices having 0 indegree
 queue = deque()
 for i in range(num_vertices):
     if indegree[i] == 0:
         queue.append(i)
 
 topo_order = []
 
 # Process vertices in BFS manner
 while queue:
     node = queue.popleft()
     topo_order.append(node)
     
     # Decrease indegree of adjacent vertices
     for neighbor in adj_list[node]:
         indegree[neighbor] -= 1
         if indegree[neighbor] == 0:
             queue.append(neighbor)
 
 # Check if topological sort is possible (no cycles)
 if len(topo_order) != num_vertices:
     return []  # Graph has a cycle
 
 return topo_order

# Example usage
if __name__ == "__main__":
 # Example: DAG with 6 vertices
 num_vertices = 6
 adj_list = [
     [2, 3],    # 0 -> 2, 3
     [3, 4],    # 1 -> 3, 4
     [5],       # 2 -> 5
     [4, 5],    # 3 -> 4, 5
     [5],       # 4 -> 5
     []         # 5 -> none
 ]
 
 result = kahns_algorithm(adj_list, num_vertices)
 
 if result:
     print("Topological Order:", result)
 else:
     print("Graph contains a cycle - topological sort not possible")

# Output: Topological Order: [0, 1, 2, 3, 4, 5]
 // kahns_algorithm.js
function kahnsAlgorithm(adjList, numVertices) {
 /**
  * Kahn's algorithm for topological sorting using BFS approach
  */
 // Calculate indegree for each vertex
 const indegree = new Array(numVertices).fill(0);
 for (let u = 0; u < numVertices; u++) {
     for (const v of adjList[u]) {
         indegree[v]++;
     }
 }
 
 // Initialize queue with vertices having 0 indegree
 const queue = [];
 for (let i = 0; i < numVertices; i++) {
     if (indegree[i] === 0) {
         queue.push(i);
     }
 }
 
 const topoOrder = [];
 
 // Process vertices in BFS manner
 while (queue.length > 0) {
     const node = queue.shift();
     topoOrder.push(node);
     
     // Decrease indegree of adjacent vertices
     for (const neighbor of adjList[node]) {
         indegree[neighbor]--;
         if (indegree[neighbor] === 0) {
             queue.push(neighbor);
         }
     }
 }
 
 // Check if topological sort is possible (no cycles)
 if (topoOrder.length !== numVertices) {
     return []; // Graph has a cycle
 }
 
 return topoOrder;
}

// Example usage
function main() {
 // Example: DAG with 6 vertices
 const numVertices = 6;
 const adjList = [
     [2, 3],    // 0 -> 2, 3
     [3, 4],    // 1 -> 3, 4
     [5],       // 2 -> 5
     [4, 5],    // 3 -> 4, 5
     [5],       // 4 -> 5
     []         // 5 -> none
 ];
 
 const result = kahnsAlgorithm(adjList, numVertices);
 
 if (result.length > 0) {
     console.log("Topological Order:", result);
 } else {
     console.log("Graph contains a cycle - topological sort not possible");
 }
}

main();

// Output: Topological Order: [0, 1, 2, 3, 4, 5]

Time Complexity

  1. Computing in-degree: O(V + E)
  2. Processing nodes using BFS: O(V + E)
  3. Time Complexity: O(V + E)

Space Complexity

  1. In-Degree Array: O(V)
  2. Queue: O(V)
  3. Space Complexity: O(V + E)

How is this guide?