Skip to content

Commit

Permalink
fix quadratic time in is_cyclic and topological_sort (fix #263) (#…
Browse files Browse the repository at this point in the history
…266)

* fix quadratic time in is_cyclic and topological_sort

* Add comments

* renaming queue to stack
  • Loading branch information
etiennedeg authored and simonschoelly committed Jul 4, 2023
1 parent c8bcea3 commit 6816f1b
Showing 1 changed file with 38 additions and 34 deletions.
72 changes: 38 additions & 34 deletions src/traversals/dfs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,30 @@ function is_cyclic end
end
# see https://github.com/mauro3/SimpleTraits.jl/issues/47#issuecomment-327880153 for syntax
@traitfn function is_cyclic(g::AG::IsDirected) where {T,AG<:AbstractGraph{T}}
# 0 if not visited, 1 if visited, 2 if in the current dfs path, 3 if fully explored
vcolor = zeros(UInt8, nv(g))
vertex_stack = Vector{T}()
for v in vertices(g)
vcolor[v] != 0 && continue
S = Vector{T}([v])
push!(vertex_stack, v)
vcolor[v] = 1
while !isempty(S)
u = S[end]
w = 0
for n in outneighbors(g, u)
if vcolor[n] == 1
return true
elseif vcolor[n] == 0
w = n
break
while !isempty(vertex_stack)
u = vertex_stack[end]
if vcolor[u] == 1
vcolor[u] = 2
for n in outneighbors(g, u)
# we hit a loop when reaching back a vertex of the main path
if vcolor[n] == 2
return true
elseif vcolor[n] == 0
# we store neighbors, but these are not yet on the path
vcolor[n] = 1
push!(vertex_stack, n)
end
end
end
if w != 0
vcolor[w] = 1
push!(S, w)
else
vcolor[u] = 2
pop!(S)
vcolor[u] = 3
pop!(vertex_stack)
end
end
end
Expand Down Expand Up @@ -85,34 +87,36 @@ graph `g` as a vector of vertices in topological order.
function topological_sort_by_dfs end
# see https://github.com/mauro3/SimpleTraits.jl/issues/47#issuecomment-327880153 for syntax
@traitfn function topological_sort_by_dfs(g::AG::IsDirected) where {T,AG<:AbstractGraph{T}}
# 0 if not visited, 1 if visited, 2 if in the current dfs path, 3 if fully explored
vcolor = zeros(UInt8, nv(g))
verts = Vector{T}()
vertex_stack = Vector{T}()
for v in vertices(g)
vcolor[v] != 0 && continue
S = Vector{T}([v])
push!(vertex_stack, v)
vcolor[v] = 1
while !isempty(S)
u = S[end]
w = 0
for n in outneighbors(g, u)
if vcolor[n] == 1
error("The input graph contains at least one loop.") # TODO 0.7 should we use a different error?
elseif vcolor[n] == 0
w = n
break
while !isempty(vertex_stack)
u = vertex_stack[end]
if vcolor[u] == 1
vcolor[u] = 2
for n in outneighbors(g, u)
# we hit a loop when reaching back a vertex of the main path
if vcolor[n] == 2
error("The input graph contains at least one loop.") # TODO 0.7 should we use a different error?
elseif vcolor[n] == 0
# we store neighbors, but these are not yet on the path
vcolor[n] = 1
push!(vertex_stack, n)
end
end
end
if w != 0
vcolor[w] = 1
push!(S, w)
else
vcolor[u] = 2
push!(verts, u)
pop!(S)
vcolor[u] = 3
pop!(vertex_stack)
pushfirst!(verts, u)
end
end
end
return reverse(verts)
return verts
end

"""
Expand Down

0 comments on commit 6816f1b

Please sign in to comment.