Skip to content

Commit ca84b20

Browse files
committed
adds topological sort
1 parent f009f67 commit ca84b20

File tree

1 file changed

+115
-0
lines changed

1 file changed

+115
-0
lines changed

sorts/TopologicalSort.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
type Dependency struct {
8+
nodeId int
9+
children []int
10+
}
11+
12+
// converts dependencies to edges
13+
func dependenciesToEdges(dependencies []Dependency) []Edge {
14+
edges := []Edge{}
15+
for _, node := range dependencies {
16+
for _, child := range node.children {
17+
edges = append(edges, Edge{start: node.nodeId, end: child})
18+
}
19+
}
20+
return edges
21+
}
22+
23+
type Edge struct {
24+
start int // start and end are node ids
25+
end int
26+
}
27+
28+
type Node struct {
29+
id int
30+
children []int
31+
selected bool
32+
incoming int
33+
}
34+
35+
// takes a list of edges as input with start and end node_ids
36+
// useful for cases like task ordering
37+
func topologicalSort(input []Edge) ([]int, [][]int) {
38+
39+
// generate a mapping for node_id and number of incoming edges
40+
incoming := make(map[int]int)
41+
for _, edge := range input {
42+
if _, ok := incoming[edge.start]; !ok {
43+
incoming[edge.start] = 0
44+
}
45+
incoming[edge.end] += 1
46+
}
47+
48+
nodes := make([]*Node, 0)
49+
for k, v := range incoming {
50+
chdn := []int{}
51+
for _, edge := range input {
52+
if edge.start == k {
53+
chdn = append(chdn, edge.end)
54+
}
55+
}
56+
nodes = append(nodes, &Node{id: k, children: chdn, selected: false, incoming: v})
57+
}
58+
59+
res := []int{}
60+
var levels [][]int
61+
for len(res) < len(nodes) {
62+
level := []int{}
63+
queue := []int{}
64+
for idx, node := range nodes {
65+
// select a node with no incoming dependency
66+
if !node.selected && node.incoming == 0 {
67+
queue = append(queue, idx)
68+
nodes[idx].selected = true
69+
}
70+
}
71+
for _, idx := range queue {
72+
node := nodes[idx]
73+
level = append(level, node.id)
74+
// decrement incoming values for all children
75+
for _, childId := range node.children {
76+
for _, child := range nodes {
77+
if !child.selected && child.id == childId {
78+
child.incoming--
79+
}
80+
}
81+
}
82+
}
83+
res = append(res, level...)
84+
levels = append(levels, level)
85+
}
86+
return res, levels
87+
}
88+
89+
func main() {
90+
var edges []Edge
91+
edges = append(edges, Edge{1, 2})
92+
edges = append(edges, Edge{2, 3})
93+
edges = append(edges, Edge{4, 3})
94+
edges = append(edges, Edge{4, 5})
95+
edges = append(edges, Edge{3, 6})
96+
edges = append(edges, Edge{5, 6})
97+
98+
order, levels := topologicalSort(edges)
99+
fmt.Println("result: ", order)
100+
fmt.Println("levels: ", levels)
101+
102+
// or you can specify dependencies
103+
var deps []Dependency
104+
deps = append(deps, Dependency{nodeId: 1, children: []int{2}})
105+
deps = append(deps, Dependency{nodeId: 2, children: []int{3}})
106+
deps = append(deps, Dependency{nodeId: 4, children: []int{3, 5}})
107+
deps = append(deps, Dependency{nodeId: 5, children: []int{6}})
108+
deps = append(deps, Dependency{nodeId: 3, children: []int{6}})
109+
110+
edges = dependenciesToEdges(deps)
111+
order, levels = topologicalSort(edges)
112+
fmt.Println("result: ", order)
113+
fmt.Println("levels: ", levels)
114+
115+
}

0 commit comments

Comments
 (0)