-
-
Notifications
You must be signed in to change notification settings - Fork 109
/
Copy pathdijkstra.jl
101 lines (84 loc) · 3.11 KB
/
dijkstra.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
"""
dijkstra(graph::Vector{Vector{Tuple{Int,Int}}}, source::Int)
Given a directed graph with weights on the arcs and a source vertex, the dijkstra algorithm
calculates the distance from the source to all other vertices, and the solution tree associated
with those distances. The solution tree is given by a vector `prev` which stores the source of the
arc that arrives at each vertex. By definition: distance[source] = prev[source] = 0. If a vertex v
is not reachable from the source, then distance[v] = prev[v] = -1.
# Arguments:
- `graph`: a directed graph with weights on the arcs
- `source`: the source vertex from which the distances will be calculated
# Example
```jldoctest
graph = [
[(2, 8), (3, 6), (4, 4)],
[(3, 1), (5, 5)],
[(5, 4)],
[(2, 3), (5, 9)],
[(1, 2), (3, 2), (4, 5)],
[(1, 1), (4, 3)],
]
distances, prev = dijkstra(graph, 1)
println("v | dist | path")
for v in eachindex(graph)
distance = distances[v] == -1 ? " NR" : lpad(distances[v], 4) # NR: Non Reachable
path = join(get_dijkstra_path(prev, v), " -> ")
println("\$v | \$distance | \$path")
end
# output
v | dist | path
1 | 0 | 1
2 | 7 | 1 -> 4 -> 2
3 | 6 | 1 -> 3
4 | 4 | 1 -> 4
5 | 10 | 1 -> 3 -> 5
6 | NR |
```
Contributed By: [Gabriel Soares](https://github.com/gosoares)
"""
function dijkstra(graph::Vector{Vector{Tuple{Int,Int}}}, source::Int)
# V = {1, 2, ..., length(graph)}: set of vertices
# A = {(i, j): i and j are adjacents; i,j in V}: set of arcs
# graph[i] = {(j, distance[i to j]): (i, j) in A}: adjacency list
# distance[j] min distance from source to j
distance::Vector{Int} = fill(typemax(Int), length(graph))
prev::Vector{Int} = fill(-1, length(graph))
visited::Vector{Bool} = falses(length(graph))
pq = MinHeap{Tuple{Int,Int}}() # (distance, vertex) | priority queue
distance[source] = 0
prev[source] = 0 # to mark the source
push!(pq, (0, source))
while !isempty(pq)
# get the vertex that was not yet visited and the distance from the source is minimal
dv, v = pop!(pq)
visited[v] && continue
visited[v] = true
for (u, dvu) in graph[v] # dvu: distance from v to u
# check if u can be reached through v with a smaller distance than the current
if !visited[u] && dv + dvu < distance[u]
distance[u] = dv + dvu
prev[u] = v
push!(pq, (distance[u], u))
end
end
end
replace!(distance, typemax(Int) => -1) # distance[v] = -1 means that v is not reachable from source
return distance, prev
end
"""
get_dijkstra_path(tree::Vector{Int}, dest::Int)
Given a solution `tree` from the [`dijkstra`](@ref) algorithm, extract the path from the source to
`dest`, including them.
# Arguments:
- `tree`: solution tree from the [`dijkstra`](@ref) algorithm
- `dest`: path's destionation vertex
"""
function get_dijkstra_path(tree::Vector{Int}, dest::Int)
path = Int[]
tree[dest] == -1 && return path # not reachable
while dest != 0
push!(path, dest)
dest = tree[dest]
end
return reverse!(path)
end