Bird
Raised Fist0
DSA Javascriptprogramming

Topological Sort Using Kahn's Algorithm BFS in DSA Javascript

Choose your learning style10 modes available
Mental Model
We find an order to do tasks where some tasks depend on others by repeatedly picking tasks with no unmet dependencies.
Analogy: Imagine you have to bake a cake but must first prepare ingredients. You start with tasks that need no preparation, then move on as dependencies clear.
Graph:
0 -> 1 -> 3
↓
2

In-degree array:
[0, 1, 1, 2]
Queue: [0]
Sorted order: []
Dry Run Walkthrough
Input: Graph edges: 0->1, 0->2, 1->3, 2->3
Goal: Find a valid order to complete tasks so all dependencies come before dependent tasks
Step 1: Calculate in-degree for each node and enqueue nodes with in-degree 0
In-degree: [0,1,1,2]
Queue: [0]
Sorted order: []
Why: We start with tasks that have no dependencies
Step 2: Dequeue 0, add to sorted order, reduce in-degree of neighbors 1 and 2
In-degree: [0,0,0,2]
Queue: [1,2]
Sorted order: [0]
Why: Completing task 0 frees tasks 1 and 2
Step 3: Dequeue 1, add to sorted order, reduce in-degree of neighbor 3
In-degree: [0,0,0,1]
Queue: [2]
Sorted order: [0,1]
Why: Completing task 1 partially frees task 3
Step 4: Dequeue 2, add to sorted order, reduce in-degree of neighbor 3
In-degree: [0,0,0,0]
Queue: [3]
Sorted order: [0,1,2]
Why: Completing task 2 fully frees task 3
Step 5: Dequeue 3, add to sorted order
In-degree: [0,0,0,0]
Queue: []
Sorted order: [0,1,2,3]
Why: All dependencies met, task 3 can be done last
Result:
Sorted order: 0 -> 1 -> 2 -> 3 -> null
Annotated Code
DSA Javascript
class Graph {
  constructor(vertices) {
    this.V = vertices;
    this.adj = new Array(vertices).fill(0).map(() => []);
  }

  addEdge(u, v) {
    this.adj[u].push(v);
  }

  kahnTopologicalSort() {
    const inDegree = new Array(this.V).fill(0);
    // Calculate in-degree of each vertex
    for (let u = 0; u < this.V; u++) {
      for (const v of this.adj[u]) {
        inDegree[v]++;
      }
    }

    const queue = [];
    // Enqueue vertices with in-degree 0
    for (let i = 0; i < this.V; i++) {
      if (inDegree[i] === 0) queue.push(i);
    }

    const topoOrder = [];
    while (queue.length > 0) {
      const u = queue.shift();
      topoOrder.push(u);
      // Decrease in-degree of neighbors
      for (const v of this.adj[u]) {
        inDegree[v]--;
        if (inDegree[v] === 0) queue.push(v);
      }
    }

    if (topoOrder.length !== this.V) {
      return "Graph has a cycle, topological sort not possible";
    }

    return topoOrder.join(' -> ') + ' -> null';
  }
}

// Driver code
const g = new Graph(4);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 3);
g.addEdge(2, 3);

console.log(g.kahnTopologicalSort());
for (let u = 0; u < this.V; u++) { for (const v of this.adj[u]) { inDegree[v]++; } }
Calculate in-degree for each vertex by counting incoming edges
for (let i = 0; i < this.V; i++) { if (inDegree[i] === 0) queue.push(i); }
Enqueue all vertices with zero in-degree to start processing
while (queue.length > 0) { const u = queue.shift(); topoOrder.push(u);
Process vertices with no dependencies, adding them to the order
for (const v of this.adj[u]) { inDegree[v]--; if (inDegree[v] === 0) queue.push(v); }
Reduce in-degree of neighbors and enqueue if they become free of dependencies
if (topoOrder.length !== this.V) { return "Graph has a cycle, topological sort not possible"; }
Check for cycles by verifying if all vertices were processed
OutputSuccess
0 -> 1 -> 2 -> 3 -> null
Complexity Analysis
Time: O(V + E) because we visit each vertex and edge once during in-degree calculation and BFS traversal
Space: O(V) for storing in-degree array, queue, and output order
vs Alternative: Compared to DFS-based topological sort, Kahn's algorithm explicitly uses in-degree and queue, which can be easier to understand and detect cycles early
Edge Cases
Graph with cycle
Algorithm detects cycle and returns a message that topological sort is not possible
DSA Javascript
if (topoOrder.length !== this.V) { return "Graph has a cycle, topological sort not possible"; }
Graph with no edges
All vertices have zero in-degree and are output in any order
DSA Javascript
for (let i = 0; i < this.V; i++) { if (inDegree[i] === 0) queue.push(i); }
Single vertex graph
Returns the single vertex as the topological order
DSA Javascript
for (let i = 0; i < this.V; i++) { if (inDegree[i] === 0) queue.push(i); }
When to Use This Pattern
When you need to order tasks with dependencies and detect cycles, use Kahn's algorithm BFS for topological sorting because it processes nodes with no unmet dependencies first.
Common Mistakes
Mistake: Not updating in-degree of neighbors after removing a node
Fix: Decrease in-degree of all neighbors and enqueue those whose in-degree becomes zero
Mistake: Not checking if all nodes are processed to detect cycles
Fix: Compare length of result with number of vertices and handle cycle case
Summary
Finds a valid order of tasks respecting dependencies using BFS and in-degree counts
Use when you have a directed acyclic graph and need to order nodes so dependencies come first
The key insight is to repeatedly pick nodes with zero in-degree and update neighbors until all nodes are processed or a cycle is detected

Practice

(1/5)
1. What is the main purpose of Kahn's Algorithm in graph theory?
easy
A. To find a topological ordering of a Directed Acyclic Graph (DAG)
B. To find the shortest path between two nodes
C. To detect cycles in an undirected graph
D. To calculate the minimum spanning tree

Solution

  1. Step 1: Understand Kahn's Algorithm goal

    Kahn's Algorithm is designed to produce a linear ordering of vertices in a Directed Acyclic Graph (DAG) such that for every directed edge u -> v, u comes before v in the ordering.
  2. Step 2: Compare with other graph algorithms

    Other algorithms like shortest path or minimum spanning tree serve different purposes, so they do not match Kahn's Algorithm's goal.
  3. Final Answer:

    To find a topological ordering of a Directed Acyclic Graph (DAG) -> Option A
  4. Quick Check:

    Topological sort = Kahn's Algorithm purpose [OK]
Hint: Kahn's Algorithm always orders DAG nodes topologically [OK]
Common Mistakes:
  • Confusing topological sort with shortest path
  • Thinking it works on undirected graphs
  • Assuming it detects cycles directly
2. Which of the following is the correct way to initialize the queue in Kahn's Algorithm in JavaScript?
easy
A. const queue = []; // Push all nodes with indegree 0
B. const queue = new Set(); // Add all nodes with indegree 0
C. const queue = {}; // Store nodes with indegree 0 as keys
D. const queue = null; // Initialize empty queue

Solution

  1. Step 1: Identify queue data structure for BFS

    Kahn's Algorithm uses a queue to process nodes with indegree 0 in order. In JavaScript, an array is commonly used as a queue by pushing and shifting elements.
  2. Step 2: Evaluate options

    const queue = []; // Push all nodes with indegree 0 correctly initializes an empty array to be used as a queue. const queue = new Set(); // Add all nodes with indegree 0 uses a Set which does not guarantee order. const queue = {}; // Store nodes with indegree 0 as keys uses an object which is not suitable as a queue. const queue = null; // Initialize empty queue initializes null which is invalid.
  3. Final Answer:

    const queue = []; // Push all nodes with indegree 0 -> Option A
  4. Quick Check:

    Queue = array for BFS in Kahn's Algorithm [OK]
Hint: Use array as queue with push and shift in JavaScript [OK]
Common Mistakes:
  • Using Set which does not preserve order
  • Using object instead of queue
  • Initializing queue as null
3. What will be the output of the following code snippet implementing Kahn's Algorithm on the graph edges [[5, 2], [5, 0], [4, 0], [4, 1], [2, 3], [3, 1]]?
function kahnTopoSort(edges) {
  const graph = {};
  const indegree = {};
  const nodes = new Set();

  edges.forEach(([u, v]) => {
    nodes.add(u);
    nodes.add(v);
    if (!graph[u]) graph[u] = [];
    graph[u].push(v);
    indegree[v] = (indegree[v] || 0) + 1;
    if (!(u in indegree)) indegree[u] = 0;
  });

  const queue = [];
  nodes.forEach(node => {
    if (indegree[node] === 0) queue.push(node);
  });

  const result = [];
  while (queue.length) {
    const node = queue.shift();
    result.push(node);
    (graph[node] || []).forEach(nei => {
      indegree[nei]--;
      if (indegree[nei] === 0) queue.push(nei);
    });
  }

  return result;
}

console.log(kahnTopoSort([[5, 2], [5, 0], [4, 0], [4, 1], [2, 3], [3, 1]]));
medium
A. [5, 4, 0, 2, 3, 1]
B. [4, 5, 0, 2, 3, 1]
C. [5, 4, 2, 0, 3, 1]
D. [4, 5, 2, 3, 1, 0]

Solution

  1. Step 1: Build graph and indegree map

    Edges create graph: 5->2,5->0,4->0,4->1,2->3,3->1. Indegree counts: 5=0,4=0,2=1,3=1,1=2,0=2.
  2. Step 2: Process nodes with indegree 0 and update

    Start queue with [5,4]. Remove 5: result=[5], decrease indegree of 2 and 0. 2 indegree=0, 0 indegree=1. Queue=[4,2]. Remove 4: result=[5,4], decrease indegree of 0 and 1. 0 indegree=0, 1 indegree=1. Queue=[2,0]. Remove 2: result=[5,4,2], decrease indegree of 3. 3 indegree=0. Queue=[0,3]. Remove 0: result=[5,4,2,0], no neighbors. Queue=[3]. Remove 3: result=[5,4,2,0,3], decrease indegree of 1. 1 indegree=0. Queue=[1]. Remove 1: result=[5,4,2,0,3,1]. Queue empty.
  3. Final Answer:

    [5, 4, 2, 0, 3, 1] -> Option C
  4. Quick Check:

    Topological order = [5,4,2,0,3,1] [OK]
Hint: Track indegree zero nodes and update after removing each node [OK]
Common Mistakes:
  • Not updating indegree correctly
  • Wrong initial queue nodes
  • Mixing order of nodes with same indegree
4. Identify the bug in this Kahn's Algorithm implementation snippet:
function kahnTopoSort(edges) {
  const graph = {};
  const indegree = {};
  edges.forEach(([u, v]) => {
    if (!graph[u]) graph[u] = [];
    graph[u].push(v);
    indegree[v] = (indegree[v] || 0) + 1;
  });
  const queue = [];
  for (const node in graph) {
    if (!indegree[node]) queue.push(node);
  }
  const result = [];
  while (queue.length) {
    const node = queue.shift();
    result.push(node);
    (graph[node] || []).forEach(nei => {
      indegree[nei]--;
      if (indegree[nei] === 0) queue.push(nei);
    });
  }
  return result;
}
medium
A. Graph edges are not added properly to adjacency list
B. Nodes with zero indegree not correctly identified because some nodes are missing in indegree
C. Queue is initialized incorrectly as an object instead of array
D. The while loop condition should be queue.length > 1

Solution

  1. Step 1: Check indegree initialization

    Indegree is only set for nodes that appear as destination (v). Nodes that only appear as source (u) are missing in indegree, so their indegree is undefined, not zero.
  2. Step 2: Identify impact on queue initialization

    The queue initialization only loops over keys in the graph object (nodes with outgoing edges). Nodes with zero indegree but no outgoing edges (e.g., isolated nodes) are missing from both the graph and indegree, so not correctly identified.
  3. Final Answer:

    Nodes with zero indegree not correctly identified because some nodes are missing in indegree -> Option B
  4. Quick Check:

    Indegree missing nodes cause wrong zero indegree detection [OK]
Hint: Initialize indegree for all nodes before queue setup [OK]
Common Mistakes:
  • Not initializing indegree for all nodes
  • Using wrong loop condition in while
  • Incorrect queue data structure
5. Given a graph with edges [[1, 2], [1, 3], [3, 4], [2, 4], [4, 5], [6, 3]], how can you modify Kahn's Algorithm to detect if the graph contains a cycle?
hard
A. Add a visited set and mark nodes visited during BFS; if revisited, cycle exists
B. Count edges and compare with nodes; if edges > nodes, cycle exists
C. Use a stack instead of queue to detect cycles during processing
D. Check if the number of nodes processed is less than total nodes; if yes, a cycle exists

Solution

  1. Step 1: Understand Kahn's Algorithm cycle detection

    Kahn's Algorithm processes nodes with zero indegree. If a cycle exists, some nodes will never reach zero indegree and thus won't be processed.
  2. Step 2: Detect cycle by comparing processed nodes count

    If the count of processed nodes is less than total nodes, it means some nodes are stuck in a cycle and were never processed, indicating a cycle.
  3. Final Answer:

    Check if the number of nodes processed is less than total nodes; if yes, a cycle exists -> Option D
  4. Quick Check:

    Processed nodes < total nodes means cycle [OK]
Hint: Compare processed nodes count with total nodes to find cycles [OK]
Common Mistakes:
  • Using visited set which is for DFS, not Kahn's Algorithm
  • Using stack instead of queue incorrectly
  • Comparing edges and nodes count wrongly
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard