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