package main import ( "fmt" ) func kahnTopoSort(vertices int, edges [][]int) []int { inDegree := make([]int, vertices) graph := make([][]int, vertices) for _, edge := range edges { graph[edge[0]] = append(graph[edge[0]], edge[1]) inDegree[edge[1]]++ } queue := []int{} for i := 0; i < vertices; i++ { if inDegree[i] == 0 { queue = append(queue, i) } } var topoOrder []int for len(queue) > 0 { node := queue[0] queue = queue[1:] topoOrder = append(topoOrder, node) for _, neighbor := range graph[node] { inDegree[neighbor]-- if inDegree[neighbor] == 0 { queue = append(queue, neighbor) } } } return topoOrder } func main() { vertices := 6 edges := [][]int{{5, 2}, {5, 0}, {4, 0}, {4, 1}, {2, 3}, {3, 1}} topo := kahnTopoSort(vertices, edges) fmt.Println(topo) }
The algorithm starts with nodes 4 and 5 which have zero incoming edges. Then it removes edges from these nodes and adds new zero in-degree nodes to the queue. The resulting order is [5, 4, 0, 2, 3, 1].
In-degree is the count of edges coming into a node. Nodes with zero in-degree have no dependencies and can be processed first.
package main import "fmt" func kahnTopoSort(vertices int, edges [][]int) []int { inDegree := make([]int, vertices) graph := make([][]int, vertices) for _, edge := range edges { graph[edge[0]] = append(graph[edge[0]], edge[1]) inDegree[edge[1]]++ } queue := []int{} for i := 0; i < vertices; i++ { if inDegree[i] == 0 { queue = append(queue, i) } } var topoOrder []int for len(queue) > 0 { node := queue[0] queue = queue[1:] topoOrder = append(topoOrder, node) for _, neighbor := range graph[node] { inDegree[neighbor]-- if inDegree[neighbor] == 0 { queue = append(queue, neighbor) } } } return topoOrder } func main() { vertices := 3 edges := [][]int{{0, 1}, {1, 2}, {2, 0}} topo := kahnTopoSort(vertices, edges) fmt.Println(topo) }
Kahn's Algorithm cannot produce a full topological order if the graph has a cycle. It returns a partial order missing nodes involved in the cycle.
Kahn's Algorithm is used to order tasks with dependencies, ensuring all prerequisite tasks are done before dependent tasks.
package main import ( "fmt" ) func kahnTopoSort(vertices int, edges [][]int) []int { inDegree := make([]int, vertices) graph := make([][]int, vertices) for _, edge := range edges { graph[edge[0]] = append(graph[edge[0]], edge[1]) inDegree[edge[1]]++ } queue := []int{} for i := 0; i < vertices; i++ { if inDegree[i] == 0 { queue = append(queue, i) } } var topoOrder []int for len(queue) > 0 { node := queue[0] queue = queue[1:] topoOrder = append(topoOrder, node) for _, neighbor := range graph[node] { inDegree[neighbor]-- if inDegree[neighbor] == 0 { queue = append(queue, neighbor) } } } return topoOrder } func main() { vertices := 8 edges := [][]int{{0, 2}, {1, 2}, {1, 3}, {3, 4}, {2, 5}, {4, 5}, {5, 6}, {6, 7}} topo := kahnTopoSort(vertices, edges) fmt.Println(topo) }
Nodes 0 and 1 have zero in-degree. The queue starts with [0,1]. Processing 1 before 0 leads to the order [1, 0, 2, 3, 4, 5, 6, 7].
