generated from devries/aoc_template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbfs.go
96 lines (78 loc) · 2.19 KB
/
bfs.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package utils
import (
"errors"
)
// BFSNotFound is returned by BreadthFirstSearch.Run when the queue empties
// without ever triggering the Graph.IsFinal function.
var BFSNotFound = errors.New("bfs: unable to find final state")
// BreadthFirstSearch is a struct that holds the state of a breadth first
// search. It holds a Queue, the visited nodes, the previous node for each
// visited node, and the distance (number of steps) to get from the start
// to each node.
type BreadthFirstSearch[T comparable] struct {
Queue []T
Visited map[T]bool
Previous map[T]T
Distance map[T]uint64
}
// A graph should implement the Graph interface in order to be exporable
// in a breadth first search.
type Graph[T comparable] interface {
// GetInitial returns the initial node
GetInitial() T
// GetNeighbors returns the neighbors of the given node
GetNeighbors(T) []T
// IsFinal returns true if the given node is the final node.
IsFinal(T) bool
}
// NewBFS creates a new BreadthFirstSearch struct initialized to being a search.
func NewBFS[T comparable]() *BreadthFirstSearch[T] {
bfs := BreadthFirstSearch[T]{[]T{}, make(map[T]bool), make(map[T]T), make(map[T]uint64)}
return &bfs
}
// Run a breadth first search on Graph g returning the final state, or an error
// if the final node is not found.
func (b *BreadthFirstSearch[T]) Run(g Graph[T]) (T, error) {
initState := g.GetInitial()
b.Queue = append(b.Queue, initState)
b.Distance[initState] = 0
// Do bfs
for len(b.Queue) > 0 {
s := b.Queue[0]
b.Queue = b.Queue[1:]
d := b.Distance[s]
if b.Visited[s] {
continue
}
b.Visited[s] = true
for _, ns := range g.GetNeighbors(s) {
if b.Visited[ns] {
continue
}
b.Distance[ns] = d + 1
b.Previous[ns] = s
if g.IsFinal(ns) {
return ns, nil
}
b.Queue = append(b.Queue, ns)
}
}
return initState, BFSNotFound
}
// GetPath return the shortest path from the initial node to the final given node.
func (b *BreadthFirstSearch[T]) GetPath(s T) []T {
ret := []T{s}
for {
ns, ok := b.Previous[s]
if !ok {
break
}
ret = append(ret, ns)
s = ns
}
// reverse
for i, j := 0, len(ret)-1; i < j; i, j = i+1, j-1 {
ret[i], ret[j] = ret[j], ret[i]
}
return ret
}