mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-24 22:08:58 -05:00
91 lines
2.1 KiB
Go
91 lines
2.1 KiB
Go
// Copyright 2016 The OPA Authors. All rights reserved.
|
|
// Use of this source code is governed by an Apache2
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package util
|
|
|
|
// Traversal defines a basic interface to perform traversals.
|
|
type Traversal interface {
|
|
|
|
// Edges should return the neighbours of node "u".
|
|
Edges(u T) []T
|
|
|
|
// Visited should return true if node "u" has already been visited in this
|
|
// traversal. If the same traversal is used multiple times, the state that
|
|
// tracks visited nodes should be reset.
|
|
Visited(u T) bool
|
|
}
|
|
|
|
// Equals should return true if node "u" equals node "v".
|
|
type Equals func(u T, v T) bool
|
|
|
|
// Iter should return true to indicate stop.
|
|
type Iter func(u T) bool
|
|
|
|
// DFS performs a depth first traversal calling f for each node starting from u.
|
|
// If f returns true, traversal stops and DFS returns true.
|
|
func DFS(t Traversal, f Iter, u T) bool {
|
|
lifo := NewLIFO(u)
|
|
for lifo.Size() > 0 {
|
|
next, _ := lifo.Pop()
|
|
if t.Visited(next) {
|
|
continue
|
|
}
|
|
if f(next) {
|
|
return true
|
|
}
|
|
for _, v := range t.Edges(next) {
|
|
lifo.Push(v)
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// BFS performs a breadth first traversal calling f for each node starting from
|
|
// u. If f returns true, traversal stops and BFS returns true.
|
|
func BFS(t Traversal, f Iter, u T) bool {
|
|
fifo := NewFIFO(u)
|
|
for fifo.Size() > 0 {
|
|
next, _ := fifo.Pop()
|
|
if t.Visited(next) {
|
|
continue
|
|
}
|
|
if f(next) {
|
|
return true
|
|
}
|
|
for _, v := range t.Edges(next) {
|
|
fifo.Push(v)
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// DFSPath returns a path from node a to node z found by performing
|
|
// a depth first traversal. If no path is found, an empty slice is returned.
|
|
func DFSPath(t Traversal, eq Equals, a, z T) []T {
|
|
p := dfsRecursive(t, eq, a, z, []T{})
|
|
for i := len(p)/2 - 1; i >= 0; i-- {
|
|
o := len(p) - i - 1
|
|
p[i], p[o] = p[o], p[i]
|
|
}
|
|
return p
|
|
}
|
|
|
|
func dfsRecursive(t Traversal, eq Equals, u, z T, path []T) []T {
|
|
if t.Visited(u) {
|
|
return path
|
|
}
|
|
for _, v := range t.Edges(u) {
|
|
if eq(v, z) {
|
|
path = append(path, z)
|
|
path = append(path, u)
|
|
return path
|
|
}
|
|
if p := dfsRecursive(t, eq, v, z, path); len(p) > 0 {
|
|
path = append(p, u)
|
|
return path
|
|
}
|
|
}
|
|
return path
|
|
}
|