Quick Overview
Kahn's algorithm repeatedly takes any node with zero remaining dependencies. If the queue empties before every node is emitted, whatever is left forms a cycle: cycle detection for free in `O(V + E)`.
A Topological Sort of a Directed Acyclic Graph (DAG) is a linear ordering of vertices such that for every directed edge u → v, vertex u comes before vertex v in the ordering.
Topological sort resolves dependencies in package managers (npm, pnpm), build systems (Webpack, Vite), and college course prerequisites.
Course Dependencies: [ Math 101 ] ──► [ Calculus ] ──► [ Machine Learning ]
[ CS 101 ] ──► [ Data Structures ] ──┘
Valid Topological Order: [ Math 101, CS 101, Calculus, Data Structures, Machine Learning ]
inDegree === 0 (nodes with no prerequisites).0, enqueue it!function topologicalSort(numCourses, prerequisites) {
const inDegree = new Array(numCourses).fill(0);
const adjList = new Map();
for (let i = 0; i < numCourses; i++) adjList.set(i, []);
for (const [course, prereq] of prerequisites) {
adjList.get(prereq).push(course);
inDegree[course]++;
}
const queue = [];
for (let i = 0; i < numCourses; i++) {
if (inDegree[i] === 0) queue.push(i);
}
const order = [];
while (queue.length > 0) {
const curr = queue.shift();
order.push(curr);
for (const neighbor of adjList.get(curr)) {
inDegree[neighbor]--;
if (inDegree[neighbor] === 0) {
queue.push(neighbor);
}
}
}
// If order contains all courses, no cycle exists!
return order.length === numCourses ? order : [];
}
console.log(topologicalSort(4, [[1, 0], [2, 0], [3, 1], [3, 2]]));
// Output: [0, 1, 2, 3] or [0, 2, 1, 3]
If the graph contains a directed cycle (e.g. A → B → A), order.length < numCourses because nodes in the cycle never reach inDegree === 0.
order.length === totalVertices to detect cycles.Use Kahn's algorithm for compilation task scheduling. Next, let's explore Dijkstra's Shortest Path Algorithm!
Big O describes how work grows, not how long it takes. An `O(N^2)` algorithm on 1,000 items does a million steps; the same work at `O(N log N)` does about 10,000.
A dynamic array doubles rather than growing by one, so the expensive copy lands on the 1st, 2nd, 4th and 8th push. Averaged across every push, that is `O(1)` amortised.
A nested loop tests every pair in `O(N^2)`. On sorted data, moving two pointers inward from both ends rules out half the remaining candidates at each step and settles it in one `O(N)` pass.