Skip to content

Commit a360b19

Browse files
committed
[FEATURE]: Add Kahn's Algorithm in Graphs #1795
1 parent 08d8c6b commit a360b19

File tree

2 files changed

+115
-0
lines changed

2 files changed

+115
-0
lines changed

Graphs/KahnsAlgorithm.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* Kahn's Algorithm for Topological Sorting (BFS-based)
3+
*
4+
* Time Complexity: O(V + E)
5+
* Space Complexity: O(V + E)
6+
*
7+
* Usage:
8+
* const V = 6;
9+
* const edges = [
10+
* [5, 2],
11+
* [5, 0],
12+
* [4, 0],
13+
* [4, 1],
14+
* [2, 3],
15+
* [3, 1]
16+
* ];
17+
* const order = kahnTopologicalSort(V, edges);
18+
* console.log(order);
19+
*
20+
* Returns:
21+
* - A valid topological order of the graph if DAG,
22+
* - [] if graph contains a cycle.
23+
*/
24+
25+
function kahnTopologicalSort(V, edges) {
26+
// Build adjacency list and indegree array
27+
const adj = Array.from({ length: V }, () => []);
28+
const indegree = new Array(V).fill(0);
29+
30+
for (const [u, v] of edges) {
31+
if (u < 0 || u >= V || v < 0 || v >= V) {
32+
throw new Error('Edge contains vertex outside range 0..V-1');
33+
}
34+
adj[u].push(v);
35+
indegree[v]++;
36+
}
37+
38+
// Initialize queue with nodes of indegree 0
39+
const queue = [];
40+
for (let i = 0; i < V; i++) {
41+
if (indegree[i] === 0) queue.push(i);
42+
}
43+
44+
const topoOrder = [];
45+
let idx = 0;
46+
while (idx < queue.length) {
47+
const node = queue[idx++]; // treat array as queue
48+
topoOrder.push(node);
49+
50+
for (const nei of adj[node]) {
51+
indegree[nei]--;
52+
if (indegree[nei] === 0) queue.push(nei);
53+
}
54+
}
55+
56+
// If topoOrder size != V, graph has a cycle
57+
if (topoOrder.length !== V) return [];
58+
59+
return topoOrder;
60+
}
61+
62+
module.exports = { kahnTopologicalSort };

Graphs/test/KahnsAlgorithm.test.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
const { kahnTopologicalSort } = require('../KahnsAlgorithm');
2+
3+
describe("Kahn's Algorithm - Topological Sort", () => {
4+
test('returns a valid topological order for a DAG', () => {
5+
const V = 6;
6+
const edges = [
7+
[5, 2],
8+
[5, 0],
9+
[4, 0],
10+
[4, 1],
11+
[2, 3],
12+
[3, 1],
13+
];
14+
15+
const order = kahnTopologicalSort(V, edges);
16+
expect(order.length).toBe(V);
17+
18+
// verify topological property
19+
const pos = new Array(V);
20+
for (let i = 0; i < order.length; i++) pos[order[i]] = i;
21+
22+
for (const [u, v] of edges) {
23+
expect(pos[u]).toBeLessThan(pos[v]);
24+
}
25+
});
26+
27+
test('returns empty array when graph contains a cycle', () => {
28+
const V = 3;
29+
const edges = [
30+
[0, 1],
31+
[1, 2],
32+
[2, 0] // cycle
33+
];
34+
const order = kahnTopologicalSort(V, edges);
35+
expect(order).toEqual([]);
36+
});
37+
38+
test('handles isolated nodes', () => {
39+
const V = 4;
40+
const edges = [
41+
[0, 1],
42+
[2, 3]
43+
];
44+
const order = kahnTopologicalSort(V, edges);
45+
expect(order.length).toBe(4);
46+
47+
const pos = new Array(V);
48+
for (let i = 0; i < order.length; i++) pos[order[i]] = i;
49+
for (const [u, v] of edges) {
50+
expect(pos[u]).toBeLessThan(pos[v]);
51+
}
52+
});
53+
});

0 commit comments

Comments
 (0)