# 42 Dijkstra’s Algorithm Written by Vincent Ngo

You can unlock the rest of this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Have you ever used the Google or Apple Maps app to find the shortest distance or fastest time from one place to another? Dijkstra’s algorithm is particularly useful in GPS networks to help find the shortest path between two places.

Dijkstra’s algorithm is a greedy algorithm. A greedy algorithm constructs a solution step-by-step, and it picks the most optimal path at every step. In particular, Dijkstra’s algorithm finds the shortest paths between vertices in either directed or undirected graphs. Given a vertex in a graph, the algorithm will find all shortest paths from the starting vertex.

Some other applications of Dijkstra’s algorithm include:

1. Communicable disease transmission: Discover where biological diseases are spreading the fastest.
2. Telephone networks: Routing calls to highest-bandwidth paths available in the network.
3. Mapping: Finding the shortest and fastest paths for travelers.

## Example

All the graphs you have looked at thus far have been undirected graphs. Let’s change it up a little and work with a directed graph! Imagine the directed graph below represents a GPS network:

The vertices represent physical locations, and the edges between the vertices represent one way paths of a given cost between locations.

In Dijkstra’s algorithm, you first choose a starting vertex, since the algorithm needs a starting point to find a path to the rest of the nodes in the graph. Assume the starting vertex you pick is vertex A.

### Eighth pass

You have covered every vertex except for H. H has two outgoing edges to G and F. However, there is no path from A to H. This is why the whole column for H is `nil`.

## Implementation

Open up the starter playground for this chapter. This playground comes with an adjacency list graph and a priority queue, which you will use to implement Dijkstra’s algorithm.

``````public enum Visit<T: Hashable> {
case start // 1
case edge(Edge<T>) // 2
}
``````
``````public class Dijkstra<T: Hashable> {

let graph: Graph

public init(graph: Graph) {
self.graph = graph
}
}
``````

### Helper methods

Before building `Dijkstra`, let’s create some helper methods that will help create the algorithm.

#### Tracing back to the start

``````private func route(to destination: Vertex<T>,
with paths: [Vertex<T> : Visit<T>]) -> [Edge<T>] {
var vertex = destination // 1
var path: [Edge<T>] = [] // 2

while let visit = paths[vertex], case .edge(let edge) = visit { // 3
path = [edge] + path // 4
vertex = edge.source // 5
}
return path // 6
}
``````

#### Calculating total distance

``````private func distance(to destination: Vertex<T>,
with paths: [Vertex<T> : Visit<T>]) -> Double {
let path = route(to: destination, with: paths) // 1
let distances = path.compactMap { \$0.weight } // 2
return distances.reduce(0.0, +) // 3
}
``````

### Generating the shortest paths

After the `distance` method, add the following:

``````public func shortestPath(from start: Vertex<T>) -> [Vertex<T> : Visit<T>] {
var paths: [Vertex<T> : Visit<T>] = [start: .start] // 1

// 2
var priorityQueue = PriorityQueue<Vertex<T>>(sort: {
self.distance(to: \$0, with: paths) <
self.distance(to: \$1, with: paths)
})
priorityQueue.enqueue(start) // 3

// to be continued
}
``````
``````while let vertex = priorityQueue.dequeue() { // 1
for edge in graph.edges(from: vertex) { // 2
guard let weight = edge.weight else { // 3
continue
}
if paths[edge.destination] == nil ||
distance(to: vertex, with: paths) + weight <
distance(to: edge.destination, with: paths) { // 4
paths[edge.destination] = .edge(edge)
priorityQueue.enqueue(edge.destination)
}
}
}

return paths
``````

### Finding a specific path

Add the following method to class `Dijkstra`:

``````public func shortestPath(to destination: Vertex<T>,
paths: [Vertex<T> : Visit<T>]) -> [Edge<T>] {
return route(to: destination, with: paths)
}
``````

``````let dijkstra = Dijkstra(graph: graph)
let pathsFromA = dijkstra.shortestPath(from: a) // 1
let path = dijkstra.shortestPath(to: d, paths: pathsFromA) // 2
for edge in path { // 3
print("\(edge.source) --|\(edge.weight ?? 0.0)|--> \(edge.destination)")
}
``````

``````A --|1.0|--> G
G --|3.0|--> C
C --|1.0|--> E
E --|2.0|--> D
``````

## Performance

In Dijkstra’s algorithm, you constructed your graph using an adjacency list. You used a min-priority queue to store vertices and extract the vertex with the minimum path. This has an overall performance of O(log V). This is because the heap operations of extracting the minimum element or inserting an element both take O(log V).

## Key points

• Dijkstra’s algorithm finds a path to the rest of the nodes given a starting vertex.
• This algorithm is useful for finding the shortest paths between different endpoints.
• `Visit` state is used to track the edges back to the start vertex.
• The priority queue data structure helps to always return the vertex with the shortest path.
• Hence, it is a greedy algorithm!

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.