1
+ // Kahn's algorithm computes a topological ordering of a directed acyclic graph (DAG).
2
+ // Time Complexity: O(V + E)
3
+ // Space Complexity: O(V + E)
4
+ // Reference: https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm
5
+ // see graph.go, topological.go, kahn_test.go
6
+
1
7
package graph
2
8
9
+ // Kahn's algorithm computes a topological ordering of a directed acyclic graph (DAG).
10
+ // `n` is the number of vertices,
11
+ // `dependencies` is a list of directed edges, where each pair [a, b] represents
12
+ // a directed edge from a to b (i.e. b depends on a).
13
+ // Vertices are assumed to be labelled 0, 1, ..., n-1.
14
+ // If the graph is not a DAG, the function returns nil.
3
15
func Kahn (n int , dependencies [][]int ) []int {
4
16
g := Graph {vertices : n , Directed : true }
17
+ // track the in-degree (number of incoming edges) of each vertex
5
18
inDegree := make ([]int , n )
6
19
20
+ // populate g with edges, increase the in-degree counts accordingly
7
21
for _ , d := range dependencies {
22
+ // make sure we don't add the same edge twice
8
23
if _ , ok := g .edges [d [0 ]][d [1 ]]; ! ok {
9
24
g .AddEdge (d [0 ], d [1 ])
10
25
inDegree [d [1 ]]++
11
26
}
12
27
}
13
28
29
+ // queue holds all vertices with in-degree 0
30
+ // these vertices have no dependency and thus can be ordered first
14
31
queue := make ([]int , 0 , n )
15
32
16
33
for i := 0 ; i < n ; i ++ {
@@ -19,12 +36,20 @@ func Kahn(n int, dependencies [][]int) []int {
19
36
}
20
37
}
21
38
39
+ // order holds a valid topological order
22
40
order := make ([]int , 0 , n )
23
41
42
+ // process the dependency-free vertices
43
+ // every time we process a vertex, we "remove" it from the graph
24
44
for len (queue ) > 0 {
45
+ // pop the first vertex from the queue
25
46
vtx := queue [0 ]
26
47
queue = queue [1 :]
48
+ // add the vertex to the topological order
27
49
order = append (order , vtx )
50
+ // "remove" all the edges coming out of this vertex
51
+ // every time we remove an edge, the corresponding in-degree reduces by 1
52
+ // if all dependencies on a vertex is removed, enqueue the vertex
28
53
for neighbour := range g .edges [vtx ] {
29
54
inDegree [neighbour ]--
30
55
if inDegree [neighbour ] == 0 {
@@ -33,6 +58,7 @@ func Kahn(n int, dependencies [][]int) []int {
33
58
}
34
59
}
35
60
61
+ // if the graph is a DAG, order should contain all the certices
36
62
if len (order ) != n {
37
63
return nil
38
64
}
0 commit comments