Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: May 23, 2025
Dijkstra’s algorithm is used to find the shortest path from a starting node to a target node in a weighted graph. The algorithm exists in many variations, which were originally used to find the shortest path between two given nodes. Now they’re more commonly used to find the shortest path from the source to all other nodes in the graph, producing a shortest path tree.
In this tutorial, we’ll learn the concept of Dijkstra’s algorithm to understand how it works. At the end of this tutorial, we’ll calculate the time complexity and compare the running time between different implementations.
2. The Algorithm
The algorithm, published in 1959 and named after its creator, Dutch computer scientist Edsger Dijkstra, can be applied to a weighted graph. The algorithm finds the shortest path tree from a single source node by building a set of nodes with minimum distances from the source.
It’s important to note the following points:
Dijkstra’s algorithm makes use of breadth-first search (BFS) to solve a single source problem. However, unlike the original BFS, it uses a priority queue instead of a normal first-in-first-out queue. Each item’s priority is the cost of reaching it from the source.
Before going into the algorithm, let’s briefly review some important definitions.
The graph has the following:
The following example illustrates an undirected graph with the weight for each edge:
To implement Dijkstra’s algorithm, we need to initialize three values:
The algorithm proceeds as follows:
Let’s go through an example before coding it with the pseudocodes.
Given the following undirected graph, we’ll calculate the shortest path between the source node and the other nodes in our graph. To begin, we mark
; for the rest of the nodes, the value will be
as we haven’t visited them yet:
At this step, we pop a node with the minimal distance (i.e., node ) from
as the current node, and mark the node
as visited (add node
to
). Next, we check the neighbors of our current node (
,
, and
) in no specific order.
At the node , we have
, so we update
. Similarly, we update
and
. In addition, we update the priority queue after recalculating the distances of these nodes:
Now we need to pick a new current node by popping from the priority queue . That node will be un-visited with the smallest minimum distance. In this case, the new current node is
with
. Then we repeat adjacent node distance calculations.
After repeating these steps until is empty, we reach the final result of the shortest-path tree:
The following pseudocode shows the details of Dijkstra’s algorithm:
algorithm Dijkstra(G, source):
// INPUT
// G = the input graph (G = (V, E))
// source = the source node
// Initialization
for v in V
initialize dist[v] = infinity
dist[source] <- 0
for v in V:
add v to Q
S <- empty set
// The main loop for the algorithm
while Q is not empty:
v <- vertex in Q with min dist[v]
remove v from Q
add v to S
for neighbour u of v:
if u is in S:
continue // if u is visited then ignore it
alt <- dist[v] + weight(v, u)
if alt < dist[u]:
dist[u] <- alt // update distance of u
update Q
return dist
For a more in-depth explanation of Dijkstra’s algorithm using pseudocodes, we can read an Overview of Dijkstra’s Algorithm. Then we can learn how to implement Dijkstra Shortest Path Algorithm in Java.
There are multiple ways we can implement this algorithm. Each way utilizes different data structures to store the graph, as well as the priority queue. Thus, the differences between these implementations leads to different time complexities.
In this section, we’ll discuss the time complexity of two main cases for Dijkstra’s implementations.
This case happens when:
Let and
be the number of edges and vertices in the graph, respectively. Then the time complexity is calculated:
This case is valid when:
First, we’ll discuss the time complexity using a binary heap. In this case, the time complexity is:
For a more in-depth overview and implementation of the binary heap, we can read the article that explains Priority Queue.
Next we’ll calculate the time complexity using a Fibonacci heap. The Fibonacci heap allows us to insert a new element in and extract the node with minimal
in
. Therefore, the time complexity will be:
Overall, the Fibonacci heap-based implementation will run at the fastest speed. Conversely, the slowest version will be the unordered list-based priority queue version. However, if the graph is well-connected (i.e., having a huge number of edges, aka, having high density), there is not much difference between these three implementations.
For a detailed comparison of the running time with different implementations, we can read the experimenting with Dijkstra’s algorithm article.
For example, the following figure illustrates the running time comparison between six variants when the number of nodes is increasing:
In this article, we discussed Dijkstra’s algorithm, a popular shortest path algorithm on the graph.
First, we learned the definition and the process of a priority queue. Then we explored an example to better understand how the algorithm works.
Finally, we examined and compared the complexity of the algorithm in three different implementations.