35
35
BFSVertexIteratorState
36
36
37
37
`BFSVertexIteratorState` is a struct to hold the current state of iteration
38
- in BFS which is needed for the `Base.iterate()` function. A queue is used to
39
- keep track of the vertices which will be visited during BFS. Since the queue
40
- can contains repetitions of already visited nodes, we also keep track of that
41
- in a `BitVector` so that to skip those nodes.
38
+ in BFS which is needed for the `Base.iterate()` function. We use two vectors,
39
+ one for the current level nodes and one from the next level nodes to visit
40
+ the graph. Since new levels can contains repetitions of already visited nodes,
41
+ we also keep track of that in a `BitVector` so as to skip those nodes.
42
42
"""
43
43
mutable struct BFSVertexIteratorState
44
44
visited:: BitVector
45
- queue:: Vector{Int}
46
- neighbor_idx:: Int
45
+ curr_level:: Vector{Int}
46
+ next_level:: Vector{Int}
47
+ node_idx:: Int
47
48
n_visited:: Int
48
49
end
49
50
@@ -58,14 +59,17 @@ First iteration to visit vertices in a graph using breadth-first search.
58
59
function Base. iterate (t:: BFSIterator{<:Integer} )
59
60
visited = falses (nv (t. graph))
60
61
visited[t. source] = true
61
- return (t. source, BFSVertexIteratorState (visited, [t. source], 1 , 1 ))
62
+ state = BFSVertexIteratorState (visited, [t. source], Int[], 0 , 0 )
63
+ return Base. iterate (t, state)
62
64
end
63
65
64
66
function Base. iterate (t:: BFSIterator{<:AbstractArray} )
65
67
visited = falses (nv (t. graph))
66
- visited[first (t. source)] = true
67
- state = BFSVertexIteratorState (visited, copy (t. source), 1 , 1 )
68
- return (first (t. source), state)
68
+ curr_level = unique (s for s in t. source)
69
+ sort! (curr_level)
70
+ visited[curr_level] .= true
71
+ state = BFSVertexIteratorState (visited, curr_level, Int[], 0 , 0 )
72
+ return Base. iterate (t, state)
69
73
end
70
74
71
75
"""
74
78
Iterator to visit vertices in a graph using breadth-first search.
75
79
"""
76
80
function Base. iterate (t:: BFSIterator , state:: BFSVertexIteratorState )
77
- graph, visited, queue = t. graph, state. visited, state. queue
78
- while ! isempty (queue)
79
- if state. n_visited == nv (graph)
80
- return nothing
81
- end
82
- # we visit the first node in the queue
83
- node_start = first (queue)
84
- if ! visited[node_start]
85
- visited[node_start] = true
86
- state. n_visited += 1
87
- return (node_start, state)
88
- end
89
- # which means we arrive here when the first node was visited.
90
- neigh = outneighbors (graph, node_start)
91
- if state. neighbor_idx <= length (neigh)
92
- node = neigh[state. neighbor_idx]
93
- # we update the idx of the neighbor we will visit,
94
- # if it is already visited, we repeat
95
- state. neighbor_idx += 1
96
- if ! visited[node]
97
- push! (queue, node)
98
- state. visited[node] = true
99
- state. n_visited += 1
100
- return (node, state)
81
+ # we fill nodes in this level
82
+ if state. node_idx == length (state. curr_level)
83
+ state. n_visited += length (state. curr_level)
84
+ state. n_visited == nv (t. graph) && return nothing
85
+ @inbounds for node in state. curr_level
86
+ for adj_node in outneighbors (t. graph, node)
87
+ if ! state. visited[adj_node]
88
+ push! (state. next_level, adj_node)
89
+ state. visited[adj_node] = true
90
+ end
101
91
end
102
- else
103
- # when the first node and its neighbors are visited
104
- # we remove the first node of the queue
105
- popfirst! (queue)
106
- state. neighbor_idx = 1
107
92
end
93
+ length (state. next_level) == 0 && return nothing
94
+ state. curr_level, state. next_level = state. next_level, empty! (state. curr_level)
95
+ sort! (state. curr_level)
96
+ state. node_idx = 0
108
97
end
98
+ # we visit all nodes in this level
99
+ state. node_idx += 1
100
+ @inbounds node = state. curr_level[state. node_idx]
101
+ return (node, state)
109
102
end
0 commit comments