Skip to content

Commit

Permalink
feat: implementation of topological sort (#399)
Browse files Browse the repository at this point in the history
  • Loading branch information
ongspxm authored Oct 24, 2021
1 parent 18451c6 commit a4ea2bb
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 2 deletions.
13 changes: 11 additions & 2 deletions graph/depthfirstsearch.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func NotExist(target int, slice []int) bool {
return true
}

func DepthFirstSearch(start, end int, nodes []int, edges [][]bool) ([]int, bool) {
func DepthFirstSearchHelper(start, end int, nodes []int, edges [][]bool, showroute bool) ([]int, bool) {
var route []int
var stack []int
startIdx := GetIdx(start, nodes)
Expand All @@ -42,7 +42,16 @@ func DepthFirstSearch(start, end int, nodes []int, edges [][]bool) ([]int, bool)
return route, true
}
}
return nil, false

if showroute {
return route, false
} else {
return nil, false
}
}

func DepthFirstSearch(start, end int, nodes []int, edges [][]bool) ([]int, bool) {
return DepthFirstSearchHelper(start, end, nodes, edges, false)
}

// func main() {
Expand Down
35 changes: 35 additions & 0 deletions graph/topological.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package graph

// Assumes that graph given is valid and possible to
// get a topo ordering.
// constraints are array of []int{a, b}, representing
// an edge going from a to b
func Topological(N int, constraints [][]int) []int {
dependencies := make([]int, N)
nodes := make([]int, N)
for i := range nodes {
nodes[i] = i
}
edges := make([][]bool, N)
for i := range edges {
edges[i] = make([]bool, N)
}

for _, c := range constraints {
a := c[0]
b := c[1]
dependencies[b]++
edges[a][b] = true
}

ans := []int{}
for s := 0; s < N; s++ {
// Only start walking from top level nodes
if dependencies[s] == 0 {
route, _ := DepthFirstSearchHelper(s, N, nodes, edges, true)
ans = append(ans, route...)
}
}

return ans
}
59 changes: 59 additions & 0 deletions graph/topological_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package graph

import (
"testing"
)

var testCases = []struct {
name string
N int
constraints [][]int
}{
{
"basic test", 2,
[][]int{{1, 0}},
},
{
"double path", 7,
[][]int{
{0, 1}, {1, 3}, {3, 5},
{0, 2}, {2, 4}, {4, 6}},
},
{
"star shape", 7,
[][]int{
{0, 1}, {0, 3}, {0, 5},
{0, 2}, {0, 4}, {0, 6}},
},
{
"tree shape", 7,
[][]int{
{0, 1}, {1, 3}, {1, 5},
{0, 2}, {2, 4}, {2, 6}},
},
}

func TestTopological(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
actual := Topological(tc.N, tc.constraints)

visited := make([]bool, tc.N)
positions := make([]int, tc.N)
for i := 0; i < tc.N; i++ {
positions[actual[i]] = i
visited[actual[i]] = true
}
for _, v := range visited {
if !v {
t.Errorf("nodes not all visited, %v", visited)
}
}
for _, c := range tc.constraints {
if positions[c[0]] > positions[c[1]] {
t.Errorf("%v dun satisfy %v", actual, c)
}
}
})
}
}

0 comments on commit a4ea2bb

Please sign in to comment.