73 implicit none;
private
116 integer,
private :: vertices
117 integer,
allocatable,
private :: adjacency_list(:, :)
118 integer,
allocatable,
private :: list_sizes(:)
121 procedure, pass(this),
public :: add_edge => graph_add_edge
122 procedure, pass(this),
public :: is_circular => graph_has_cycle_dfs
139 module procedure :: graph_new
145 type(
digraph) function graph_new(vertices) result(that)
146 integer,
intent(in) :: vertices
149 that%vertices = vertices
150 allocate(that%adjacency_list(vertices, vertices), source=0)
151 allocate(that%list_sizes(vertices), source=0)
169 subroutine graph_add_edge(this, source, destination, overflow)
170 class(
digraph),
intent(inout) :: this
171 integer,
intent(in) :: source
172 integer,
intent(in) :: destination
173 logical,
intent(out),
optional :: overflow
175 if (source < 1 .or. source > this%vertices .or. &
176 destination < 1 .or. destination > this%vertices)
then
180 this%list_sizes(source) = this%list_sizes(source) + 1
181 if (this%list_sizes(source) <= this%vertices)
then
182 if (
present(overflow)) overflow = this%adjacency_list(source, this%list_sizes(source)) /= 0
183 this%adjacency_list(source, this%list_sizes(source)) = destination
202 logical function graph_has_cycle_dfs(this, start_vertex)
result(has_cycle)
203 class(
digraph),
intent(in) :: this
204 integer,
intent(in) :: start_vertex
206 logical,
allocatable :: visited(:), recursion_stack(:)
208 if (start_vertex < 1 .or. start_vertex > this%vertices)
then
213 allocate(visited(this%vertices), source=.false.)
214 allocate(recursion_stack(this%vertices), source=.false.)
216 has_cycle = dfs_recursive(this, start_vertex, visited, recursion_stack)
218 deallocate(visited, recursion_stack)
228 recursive logical function dfs_recursive(this, vertex, visited, recursion_stack)
result(has_cycle)
229 class(
digraph),
intent(in) :: this
230 integer,
intent(in) :: vertex
231 logical,
intent(inout) :: visited(:), recursion_stack(:)
232 integer :: neighbor, i
234 visited(vertex) = .true.
235 recursion_stack(vertex) = .true.
237 do i = 1, this%list_sizes(vertex)
238 neighbor = this%adjacency_list(vertex, i)
239 if (neighbor < 1 .or. neighbor > this%vertices) cycle
240 if (.not. visited(neighbor))
then
241 if (dfs_recursive(this, neighbor, visited, recursion_stack))
then
245 else if (recursion_stack(neighbor))
then
251 recursion_stack(vertex) = .false.
261 subroutine graph_final(this)
262 type(
digraph),
intent(inout) :: this
263 if (
allocated(this%adjacency_list))
deallocate(this%adjacency_list)
264 if (
allocated(this%list_sizes))
deallocate(this%list_sizes)
Directed graph supporting efficient cycle detection.