github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/graph/traverse/traverse.go (about) 1 // Copyright ©2015 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package traverse 6 7 import ( 8 "github.com/jingcheng-WU/gonum/graph" 9 "github.com/jingcheng-WU/gonum/graph/internal/linear" 10 "github.com/jingcheng-WU/gonum/graph/internal/set" 11 ) 12 13 var _ Graph = graph.Graph(nil) 14 15 // Graph is the subset of graph.Graph necessary for graph traversal. 16 type Graph interface { 17 // From returns all nodes that can be reached directly 18 // from the node with the given ID. 19 From(id int64) graph.Nodes 20 21 // Edge returns the edge from u to v, with IDs uid and vid, 22 // if such an edge exists and nil otherwise. The node v 23 // must be directly reachable from u as defined by 24 // the From method. 25 Edge(uid, vid int64) graph.Edge 26 } 27 28 // BreadthFirst implements stateful breadth-first graph traversal. 29 type BreadthFirst struct { 30 // Visit is called on all nodes on their first visit. 31 Visit func(graph.Node) 32 33 // Traverse is called on all edges that may be traversed 34 // during the walk. This includes edges that would hop to 35 // an already visited node. 36 // 37 // The value returned by Traverse determines whether 38 // an edge can be traversed during the walk. 39 Traverse func(graph.Edge) bool 40 41 queue linear.NodeQueue 42 visited set.Int64s 43 } 44 45 // Walk performs a breadth-first traversal of the graph g starting from the given node, 46 // depending on the Traverse field and the until parameter if they are non-nil. 47 // The traversal follows edges for which Traverse(edge) is true and returns the first node 48 // for which until(node, depth) is true. During the traversal, if the Visit field is 49 // non-nil, it is called with each node the first time it is visited. 50 func (b *BreadthFirst) Walk(g Graph, from graph.Node, until func(n graph.Node, d int) bool) graph.Node { 51 if b.visited == nil { 52 b.visited = make(set.Int64s) 53 } 54 b.queue.Enqueue(from) 55 if b.Visit != nil && !b.visited.Has(from.ID()) { 56 b.Visit(from) 57 } 58 b.visited.Add(from.ID()) 59 60 var ( 61 depth int 62 children int 63 untilNext = 1 64 ) 65 for b.queue.Len() > 0 { 66 t := b.queue.Dequeue() 67 if until != nil && until(t, depth) { 68 return t 69 } 70 tid := t.ID() 71 to := g.From(tid) 72 for to.Next() { 73 n := to.Node() 74 nid := n.ID() 75 if b.Traverse != nil && !b.Traverse(g.Edge(tid, nid)) { 76 continue 77 } 78 if b.visited.Has(nid) { 79 continue 80 } 81 if b.Visit != nil { 82 b.Visit(n) 83 } 84 b.visited.Add(nid) 85 children++ 86 b.queue.Enqueue(n) 87 } 88 if untilNext--; untilNext == 0 { 89 depth++ 90 untilNext = children 91 children = 0 92 } 93 } 94 95 return nil 96 } 97 98 // WalkAll calls Walk for each unvisited node of the graph g using edges independent 99 // of their direction. The functions before and after are called prior to commencing 100 // and after completing each walk if they are non-nil respectively. The function 101 // during is called on each node as it is traversed. 102 func (b *BreadthFirst) WalkAll(g graph.Undirected, before, after func(), during func(graph.Node)) { 103 b.Reset() 104 nodes := g.Nodes() 105 for nodes.Next() { 106 from := nodes.Node() 107 if b.Visited(from) { 108 continue 109 } 110 if before != nil { 111 before() 112 } 113 b.Walk(g, from, func(n graph.Node, _ int) bool { 114 if during != nil { 115 during(n) 116 } 117 return false 118 }) 119 if after != nil { 120 after() 121 } 122 } 123 } 124 125 // Visited returned whether the node n was visited during a traverse. 126 func (b *BreadthFirst) Visited(n graph.Node) bool { 127 return b.visited.Has(n.ID()) 128 } 129 130 // Reset resets the state of the traverser for reuse. 131 func (b *BreadthFirst) Reset() { 132 b.queue.Reset() 133 b.visited = nil 134 } 135 136 // DepthFirst implements stateful depth-first graph traversal. 137 type DepthFirst struct { 138 // Visit is called on all nodes on their first visit. 139 Visit func(graph.Node) 140 141 // Traverse is called on all edges that may be traversed 142 // during the walk. This includes edges that would hop to 143 // an already visited node. 144 // 145 // The value returned by Traverse determines whether an 146 // edge can be traversed during the walk. 147 Traverse func(graph.Edge) bool 148 149 stack linear.NodeStack 150 visited set.Int64s 151 } 152 153 // Walk performs a depth-first traversal of the graph g starting from the given node, 154 // depending on the Traverse field and the until parameter if they are non-nil. 155 // The traversal follows edges for which Traverse(edge) is true and returns the first node 156 // for which until(node) is true. During the traversal, if the Visit field is non-nil, it 157 // is called with each node the first time it is visited. 158 func (d *DepthFirst) Walk(g Graph, from graph.Node, until func(graph.Node) bool) graph.Node { 159 if d.visited == nil { 160 d.visited = make(set.Int64s) 161 } 162 d.stack.Push(from) 163 if d.Visit != nil && !d.visited.Has(from.ID()) { 164 d.Visit(from) 165 } 166 d.visited.Add(from.ID()) 167 168 for d.stack.Len() > 0 { 169 t := d.stack.Pop() 170 if until != nil && until(t) { 171 return t 172 } 173 tid := t.ID() 174 to := g.From(tid) 175 for to.Next() { 176 n := to.Node() 177 nid := n.ID() 178 if d.Traverse != nil && !d.Traverse(g.Edge(tid, nid)) { 179 continue 180 } 181 if d.visited.Has(nid) { 182 continue 183 } 184 if d.Visit != nil { 185 d.Visit(n) 186 } 187 d.visited.Add(nid) 188 d.stack.Push(n) 189 } 190 } 191 192 return nil 193 } 194 195 // WalkAll calls Walk for each unvisited node of the graph g using edges independent 196 // of their direction. The functions before and after are called prior to commencing 197 // and after completing each walk if they are non-nil respectively. The function 198 // during is called on each node as it is traversed. 199 func (d *DepthFirst) WalkAll(g graph.Undirected, before, after func(), during func(graph.Node)) { 200 d.Reset() 201 nodes := g.Nodes() 202 for nodes.Next() { 203 from := nodes.Node() 204 if d.Visited(from) { 205 continue 206 } 207 if before != nil { 208 before() 209 } 210 d.Walk(g, from, func(n graph.Node) bool { 211 if during != nil { 212 during(n) 213 } 214 return false 215 }) 216 if after != nil { 217 after() 218 } 219 } 220 } 221 222 // Visited returned whether the node n was visited during a traverse. 223 func (d *DepthFirst) Visited(n graph.Node) bool { 224 return d.visited.Has(n.ID()) 225 } 226 227 // Reset resets the state of the traverser for reuse. 228 func (d *DepthFirst) Reset() { 229 d.stack = d.stack[:0] 230 d.visited = nil 231 }