Topological Sort Using Kahn's Algorithm BFS in DSA Javascript - Time & Space Complexity
We want to understand how the time needed to run Kahn's Algorithm grows as the graph gets bigger.
Specifically, how does the number of nodes and edges affect the work done?
Analyze the time complexity of the following code snippet.
function kahnTopologicalSort(graph) {
const inDegree = new Map();
const queue = [];
const result = [];
for (const node of graph.keys()) {
inDegree.set(node, 0);
}
for (const [node, neighbors] of graph.entries()) {
for (const neighbor of neighbors) {
inDegree.set(neighbor, (inDegree.get(neighbor) || 0) + 1);
}
}
for (const [node, degree] of inDegree.entries()) {
if (degree === 0) queue.push(node);
}
while (queue.length > 0) {
const current = queue.shift();
result.push(current);
for (const neighbor of graph.get(current) || []) {
inDegree.set(neighbor, inDegree.get(neighbor) - 1);
if (inDegree.get(neighbor) === 0) queue.push(neighbor);
}
}
return result;
}
This code performs a topological sort on a directed graph using Kahn's Algorithm with BFS.
Look for loops and repeated steps that take most time.
- Primary operation: Visiting each node and its edges once.
- How many times: Each node is processed once; each edge is checked once.
As the graph grows, the work grows with the number of nodes and edges.
| Input Size (n nodes, e edges) | Approx. Operations |
|---|---|
| 10 nodes, 15 edges | About 25 operations (10 nodes + 15 edges) |
| 100 nodes, 200 edges | About 300 operations (100 + 200) |
| 1000 nodes, 5000 edges | About 6000 operations (1000 + 5000) |
Pattern observation: The work grows roughly by adding nodes and edges, so it grows linearly with both.
Time Complexity: O(n + e)
This means the time grows linearly with the number of nodes plus the number of edges in the graph.
[X] Wrong: "The algorithm is O(n²) because of the nested loops."
[OK] Correct: Each edge and node is visited only once, so loops do not multiply to n squared; they add up to n plus e.
Understanding this time complexity helps you explain how graph algorithms handle large data efficiently, a key skill in many coding challenges.
"What if the graph is represented as an adjacency matrix instead of adjacency lists? How would the time complexity change?"
Practice
Solution
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.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.Final Answer:
To find a topological ordering of a Directed Acyclic Graph (DAG) -> Option AQuick Check:
Topological sort = Kahn's Algorithm purpose [OK]
- Confusing topological sort with shortest path
- Thinking it works on undirected graphs
- Assuming it detects cycles directly
Solution
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.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.Final Answer:
const queue = []; // Push all nodes with indegree 0 -> Option AQuick Check:
Queue = array for BFS in Kahn's Algorithm [OK]
- Using Set which does not preserve order
- Using object instead of queue
- Initializing queue as null
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]]));Solution
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.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.Final Answer:
[5, 4, 2, 0, 3, 1] -> Option CQuick Check:
Topological order = [5,4,2,0,3,1] [OK]
- Not updating indegree correctly
- Wrong initial queue nodes
- Mixing order of nodes with same indegree
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;
}Solution
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.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.Final Answer:
Nodes with zero indegree not correctly identified because some nodes are missing in indegree -> Option BQuick Check:
Indegree missing nodes cause wrong zero indegree detection [OK]
- Not initializing indegree for all nodes
- Using wrong loop condition in while
- Incorrect queue data structure
Solution
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.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.Final Answer:
Check if the number of nodes processed is less than total nodes; if yes, a cycle exists -> Option DQuick Check:
Processed nodes < total nodes means cycle [OK]
- Using visited set which is for DFS, not Kahn's Algorithm
- Using stack instead of queue incorrectly
- Comparing edges and nodes count wrongly
Ready to prove it?
Pass the test and this pattern moves unknown
