blob: fa45c290eb309fb34f59137ab0f04d01e209c050 [file] [log] [blame]
package goraph
// BFS does breadth-first search, and returns the list of vertices.
// (https://en.wikipedia.org/wiki/Breadth-first_search)
//
// 0. BFS(G, v):
// 1.
// 2. let Q be a queue
// 3. Q.push(v)
// 4. label v as visited
// 5.
// 6. while Q is not empty:
// 7.
// 8. u = Q.dequeue()
// 9.
// 10. for each vertex w adjacent to u:
// 11.
// 12. if w is not visited yet:
// 13. Q.push(w)
// 14. label w as visited
//
func BFS(g Graph, id ID) []ID {
if g.GetNode(id) == nil {
return nil
}
q := []ID{id}
visited := make(map[ID]bool)
visited[id] = true
rs := []ID{id}
// while Q is not empty:
for len(q) != 0 {
u := q[0]
q = q[1:len(q):len(q)]
// for each vertex w adjacent to u:
cmap, _ := g.GetTargets(u)
for _, w := range cmap {
// if w is not visited yet:
if _, ok := visited[w.ID()]; !ok {
q = append(q, w.ID()) // Q.push(w)
visited[w.ID()] = true // label w as visited
rs = append(rs, w)
}
}
pmap, _ := g.GetSources(u)
for _, w := range pmap {
// if w is not visited yet:
if _, ok := visited[w.ID()]; !ok {
q = append(q, w.ID()) // Q.push(w)
visited[w.ID()] = true // label w as visited
rs = append(rs, w.ID())
}
}
}
return rs
}
// DFS does depth-first search, and returns the list of vertices.
// (https://en.wikipedia.org/wiki/Depth-first_search)
//
// 0. DFS(G, v):
// 1.
// 2. let S be a stack
// 3. S.push(v)
// 4.
// 5. while S is not empty:
// 6.
// 7. u = S.pop()
// 8.
// 9. if u is not visited yet:
// 10.
// 11. label u as visited
// 12.
// 13. for each vertex w adjacent to u:
// 14.
// 15. if w is not visited yet:
// 16. S.push(w)
//
func DFS(g Graph, id ID) []ID {
if g.GetNode(id) == nil {
return nil
}
s := []ID{id}
visited := make(map[ID]bool)
rs := []ID{}
// while S is not empty:
for len(s) != 0 {
u := s[len(s)-1]
s = s[:len(s)-1 : len(s)-1]
// if u is not visited yet:
if _, ok := visited[u]; !ok {
// label u as visited
visited[u] = true
rs = append(rs, u)
// for each vertex w adjacent to u:
cmap, _ := g.GetTargets(u)
for _, w := range cmap {
// if w is not visited yet:
if _, ok := visited[w.ID()]; !ok {
s = append(s, w.ID()) // S.push(w)
}
}
pmap, _ := g.GetSources(u)
for _, w := range pmap {
// if w is not visited yet:
if _, ok := visited[w.ID()]; !ok {
s = append(s, w.ID()) // S.push(w)
}
}
}
}
return rs
}
// DFSRecursion does depth-first search recursively.
//
// 0. DFS(G, v):
// 1.
// 2. if v is visited:
// 3. return
// 4.
// 5. label v as visited
// 6.
// 7. for each vertex u adjacent to v:
// 8.
// 9. if u is not visited yet:
// 10. recursive DFS(G, u)
//
func DFSRecursion(g Graph, id ID) []ID {
if g.GetNode(id) == nil {
return nil
}
visited := make(map[ID]bool)
rs := []ID{}
dfsRecursion(g, id, visited, &rs)
return rs
}
func dfsRecursion(g Graph, id ID, visited map[ID]bool, rs *[]ID) {
// base case of recursion
//
// if v is visited:
if _, ok := visited[id]; ok {
return
}
// label v as visited
visited[id] = true
*rs = append(*rs, id)
// for each vertex u adjacent to v:
cmap, _ := g.GetTargets(id)
for _, u := range cmap {
// if u is not visited yet:
if _, ok := visited[u.ID()]; !ok {
// recursive DFS(G, u)
dfsRecursion(g, u.ID(), visited, rs)
}
}
pmap, _ := g.GetSources(id)
for _, u := range pmap {
// if u is not visited yet:
if _, ok := visited[u.ID()]; !ok {
// recursive DFS(G, u)
dfsRecursion(g, u.ID(), visited, rs)
}
}
}