File tree Expand file tree Collapse file tree 2 files changed +115
-0
lines changed Expand file tree Collapse file tree 2 files changed +115
-0
lines changed Original file line number Diff line number Diff line change
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 } ;
Original file line number Diff line number Diff line change
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
+ } ) ;
You can’t perform that action at this time.
0 commit comments