Dijkstra’s is a pathfinding algorithm used on graphs. As opposed to other algorithms like BFS, Dijkstra’s takes into account edge weight. It is considered a greedy algorithm. Dijkstra’s is guaranteed to find the shortest path in between two nodes in a weighted graph with no negative weights.
Variations
- Can be used on weighted vs unweighted graphs.
- Can be used on both cyclic and acyclic graphs.
Idea
The idea behind Dijkstra’s algorithm is to keep track of the current smallest known distance from a source node to every other node in the graph. To do so, we usually use an array or vector called dist to keep track where dist[u] is the shortest known distance from the source node to the node u.
Then, for every node in the graph, we look at each edge and check if there are any other paths leading to that node that are shorter. Because all edge weights are non-negative, once a shortest path to a node is found, no alternative paths can be shorter.
Implementation
Where dist is an array of distances from they of source vertex to that vertex.
Where prev is an array of pointers to the node predecessing the note at that index
Pseudocode
Dijkstra(Graph, source)
PQ <- PQ/minheap storing vertex priority
dist[source] <- 0
PQ.add(source, 0) //add and heapify?
// set all vertices to have infinite distance to source
// and an undefined parent node
for each vertex v in Graph.Vertices
if v != source
prev[v] = undefined
dist[v] = infinity
PQ.add(v, INFINITY)
while PQ != empty
u = PQ.min //Top of the heap, so would also be PQ[0]
for each edge e (u, v)
//alternative distance from source node to all the possible edges
alt = dist[u] + Graph.edge(u, v)
// if the alternative path is smaller than current tracked
if alt < dist[v]
// set the prev to the current prev node
// and set that distance as current smallest path
prev[v] = u
dist[v] = alt
PQ.decrease_prio(v, alt)
return (dist, prev)
It seems like Dijkstra’s is implemented with a priority queue minheap that locally keeps track of the shortest path from the current vertex to the nearest other vertex.
It also keeps track of a predecessor node for some reason.
Ah it’s because the process of finding a path from one to the other is by building a data structure that contains all nodes with what node is the cheapest to get to that node by. Then, you can backtrack your way from the destination to the start.
C++ Implementation
vector<int> dijkstra(vector<vector<pair<int,int>>>& adj, int src) {
int numberOfVertices = adj.size();
// Min-heap (priority queue) storing pairs of (distance, node)
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
// Initialize all distances to int_max or infinity
vector<int> dist(numberOfVertices, INT_MAX);
// Distance from source to itself is 0
dist[src] = 0;
pq.emplace(0, src);
// Process the queue until all reachable vertices are finalized
while (!pq.empty()) {
// Grab the top element, i.e., consider the shortest known path
auto top = pq.top();
pq.pop();
int distance = top.first;
int node = top.second;
// If this distance not the latest shortest one, skip it
if (distance > dist[node])
continue;
// Explore all neighbors of the current node
for (auto &p : adj[node]) {
int vertex = p.first;
int weight = p.second;
// If we found a shorter path to v through u, update it
if (dist[node] + weight < dist[vertex]) {
dist[vertex] = dist[node] + weight;
pq.emplace(dist[vertex], vertex);
}
}
}
// Return the final shortest distances from the source
return dist;
}Tip
As usual, CPSC 221 doesn’t really expect you to know how to implement Dijkstra’s off the top of your dome. You just have to understand it conceptually and how it works.
Data Structures
Dijkstra’s requires:
- Priority queue/minheap
- Indexed heap
And the total look up cost is