Exploring Dijkstra’s Algorithm: Step-by-Step Guide to Finding the Shortest Path
Updated on Apr 24, 2025 | 19 min read | 3.77K+ views
Share:
For working professionals
For fresh graduates
More
Updated on Apr 24, 2025 | 19 min read | 3.77K+ views
Share:
Table of Contents
Dijkstra’s Algorithm is a graph search algorithm that finds the shortest path between two points in a network, making it essential for navigation and routing systems. However, understanding how it works can be tricky without a clear guide.
This article will break down the process with a practical dijkstra's shortest path algorithm example. You'll learn the concept step by step and see how to apply it in real-world scenarios. Let’s dive in!
Imagine you’re navigating a map with various cities connected by roads of different lengths, and you need to find the shortest route between two cities. The algorithm finds the shortest path by exploring nodes with the smallest known distance, updating paths until it reaches the destination.
Here’s how the algorithm works:
1. Initialize: Start with the source node, setting its distance to zero and all other nodes' distances to infinity.
2. Visit the Nearest Node: Choose the node with the smallest known distance and explore its neighbors.
3. Update Distances: For each neighboring node, check if the new path is shorter than the previously known path.
4. Repeat: Visit the nearest node, update distances, and continue until all nodes are explored or the destination is reached.
Before we jump into the dijkstra's algorithm example, let's clarify some important fundamental terms:
Let’s break this down with a simple dijkstra's algorithm example. Suppose you have four cities (A, B, C, D), and we need to find the shortest path from city A to city D. The roads between them have different lengths:
Now, let’s apply Dijkstra’s shortest path algorithm.
Step 1: Initialize the distances
Start with the source city (A). Set the distance to A as 0 and all others as infinity:
A |
B |
C |
D |
0 | ∞ | ∞ | ∞ |
Step 2: Visit the nearest node (A)
From city A, the only two reachable cities are B and C. Update their distances:
A |
B |
C |
D |
0 | 5 | 10 | ∞ |
Step 3: Visit the next nearest node (B)
Next, choose the city with the smallest distance: city B. From B, we can reach C and D:
A |
B |
C |
D |
0 | 5 | 8 | 7 |
Step 4: Visit the next nearest node (D)
Now, visit city D because it has the smallest distance (7). From D, there’s no shorter path to any other city, so we can move on to the final step.
Step 5: Reach the destination
At this point, we’ve found the shortest path to city D, and the total distance is 7.
To make it even clearer, here’s a simple visual diagram:
This visual shows the cities (nodes) and roads (edges) between them, along with the weights (distances) marked on the edges.
The shortest path from A to D is A → B → D, with a total distance of 7.
Pseudocode for Dijkstra’s Algorithm
1. Initialize the distances: set all nodes to infinity except for the starting node.
2. Create a priority queue and add the starting node with a distance of 0.
3. While the queue is not empty:
a. Remove the node with the smallest distance.
b. Update the neighbors' distances if a shorter path is found.
c. Add the neighbors to the queue if necessary.
4. Repeat until all nodes are processed or the destination is reached.
This algorithm is invaluable for tasks like optimizing network routes or planning efficient travel paths.
Also Read: What is Kruskal’s Algorithm? Steps, Examples, Overview
Now that you’ve got the theory down, it’s time to turn those concepts into code.
There are several ways to approach Dijkstra’s Algorithm, each varying in complexity and efficiency. From simple arrays to more advanced data structures like priority queues, your chosen method can significantly impact the algorithm's performance, especially in large-scale problems.
One of the most straightforward and commonly used approaches is implementing Dijkstra’s Algorithm with an adjacency matrix.
A common approach to implementing Dijkstra’s Algorithm is using an adjacency matrix, which represents the graph as a 2D array. Each element shows the weight of the edge between nodes, with infinity indicating no edge.
This method is intuitive and works well for dense graphs, where most nodes are connected. However, for larger graphs, its space complexity can become inefficient.
Step-by-Step Explanation
Let’s break down how Dijkstra’s Algorithm works when implemented with an adjacency matrix.
1. Initialize the Matrix: Create a matrix where each element represents the edge weight between nodes. If no edge exists, set the value to infinity. The diagonal is set to 0, representing the distance from a node to itself.
2. Distance Array: Initialize an array to store the shortest distance from the starting node to all others. Set the starting node’s distance to 0 and all others to infinity.
3. Visited Array: Create an array to track visited nodes, preventing revisits and ensuring efficiency during the algorithm.
4. Iterate through Nodes: For each unvisited node, calculate the tentative distance through its neighbors. If a shorter path is found, update the distance.
5. Repeat: Continue this process until the shortest path to all nodes has been determined.
Code Example
import sys
# Function to implement Dijkstra's Algorithm using an adjacency matrix
def dijkstra(matrix, start_node):
n = len(matrix) # Number of nodes
dist = [sys.maxsize] * n # Initialize all distances to infinity
dist[start_node] = 0 # Distance to start node is 0
visited = [False] * n # To keep track of visited nodes
for _ in range(n):
# Find the node with the minimum distance that hasn't been visited
min_dist = sys.maxsize
min_index = -1
for i in range(n):
if not visited[i] and dist[i] < min_dist:
min_dist = dist[i]
min_index = i
visited[min_index] = True # Mark the node as visited
# Update distances for the neighbors of the current node
for j in range(n):
if not visited[j] and matrix[min_index][j] != sys.maxsize:
new_dist = dist[min_index] + matrix[min_index][j]
if new_dist < dist[j]:
dist[j] = new_dist
return dist
# Example graph represented by an adjacency matrix
# Example: 0,1,2,3,4 are nodes and values represent the edge weights
graph = [ [0, 5, sys.maxsize, sys.maxsize, 10],
[5, 0, 3, sys.maxsize, sys.maxsize],
[sys.maxsize, 3, 0, 1, sys.maxsize],
[sys.maxsize, sys.maxsize, 1, 0, 2],
[10, sys.maxsize, sys.maxsize, 2, 0]
]
# Running Dijkstra's Algorithm from node 0
start_node = 0
distances = dijkstra(graph, start_node)
print("Shortest distances from node 0:", distances)
Output:
Shortest distances from node 0: [0, 5, 8, 7, 7]
Explanation of Code:
Time Complexity
The time complexity of Dijkstra’s Algorithm using an adjacency matrix is O(n^2), where n is the number of nodes.
This is due to the algorithm needing to examine each of the n nodes and check all other n nodes to find the one with the smallest tentative distance.
While this approach is efficient for small graphs, its quadratic time complexity can lead to slower performance as the number of nodes increases, making it less suitable for large graphs.
Pros:
Cons:
An adjacency list is a more efficient graph representation compared to the adjacency matrix. Instead of using a 2D array to represent all possible edges, an adjacency list stores each node’s neighbors along with the corresponding edge weights.
This representation is especially useful for sparse graphs, where most nodes are not connected. Using an adjacency list can reduce space complexity and improve the algorithm’s performance in large graphs.
Step-by-Step Explanation
1. Initialize the List: For each node, create a list that stores its neighbors and the corresponding edge weights. If a node has no neighbors, its list is empty.
2. Distance Array: Create an array to store the shortest distance from the starting node to all other nodes. Set the distance of the starting node to 0 and all others to infinity.
3. Visited Array: Use a visited array to track nodes that have already been processed. This ensures we don’t revisit nodes and improves efficiency.
4. Iterate through Nodes: For each unvisited node, explore its neighbors. Calculate the tentative distance to each neighbor and update the shortest distance if a shorter path is found.
5. Repeat: Continue the process until the shortest path to all nodes has been determined.
Code Example
import heapq
def dijkstra(adj_list, start_node):
n = len(adj_list)
dist = [float('inf')] * n
dist[start_node] = 0
visited = [False] * n
min_heap = [(0, start_node)] # (distance, node)
while min_heap:
current_dist, current_node = heapq.heappop(min_heap)
if visited[current_node]:
continue
visited[current_node] = True
for neighbor, weight in adj_list[current_node]:
if visited[neighbor]:
continue
new_dist = current_dist + weight
if new_dist < dist[neighbor]:
dist[neighbor] = new_dist
heapq.heappush(min_heap, (new_dist, neighbor))
return dist
# Example graph represented as an adjacency list
# Example: 0,1,2,3,4 are nodes and values represent the edge weights
graph = [ [(1, 5), (4, 10)], # Node 0
[(0, 5), (2, 3)], # Node 1
[(1, 3), (3, 1)], # Node 2
[(2, 1), (4, 2)], # Node 3
[(0, 10), (3, 2)] # Node 4
]
# Running Dijkstra's Algorithm from node 0
start_node = 0
distances = dijkstra(graph, start_node)
print("Shortest distances from node 0:", distances)
Output:
Shortest distances from node 0: [0, 5, 8, 7, 7]
Explanation:
Pros:
Cons:
When implementing Dijkstra’s Algorithm, one common optimization is using a min-heap (priority queue) to improve the algorithm’s efficiency. In earlier approaches, we manually searched for the node with the smallest distance, which could be time-consuming, especially for large graphs.
By using a priority queue, we can automatically retrieve the smallest distance node in O(log V) time, drastically improving performance.
Step-by-Step Explanation
1. Priority Queue Initialization: Use a priority queue (min-heap) to store the nodes with their current shortest distance. This allows us to efficiently extract the node with the smallest distance.
2. Distance Array: Initialize the distance array with infinity, setting the distance to the starting node as 0.
3. Visited Array: Keep track of visited nodes to avoid re-processing them.
4. Process Nodes: Extract the node with the smallest tentative distance from the priority queue. For each of its neighbors, calculate the new distance and, if it’s shorter, update the distance and add the neighbor to the priority queue.
5. Repeat: Continue processing nodes until the shortest path to all nodes has been determined.
Code Example
import heapq
def dijkstra_min_heap(adj_list, start_node):
n = len(adj_list)
dist = [float('inf')] * n
dist[start_node] = 0
visited = [False] * n
min_heap = [(0, start_node)] # (distance, node)
while min_heap:
current_dist, current_node = heapq.heappop(min_heap)
if visited[current_node]:
continue
visited[current_node] = True
for neighbor, weight in adj_list[current_node]:
if visited[neighbor]:
continue
new_dist = current_dist + weight
if new_dist < dist[neighbor]:
dist[neighbor] = new_dist
heapq.heappush(min_heap, (new_dist, neighbor))
return dist
# Example graph represented as an adjacency list
graph = [ [(1, 5), (4, 10)], # Node 0
[(0, 5), (2, 3)], # Node 1
[(1, 3), (3, 1)], # Node 2
[(2, 1), (4, 2)], # Node 3
[(0, 10), (3, 2)] # Node 4
]
# Running Dijkstra's Algorithm with min-heap from node 0
start_node = 0
distances = dijkstra_min_heap(graph, start_node)
print("Shortest distances from node 0:", distances)
Output:
Shortest distances from node 0: [0, 5, 8, 7, 7]
Explanation:
Time Complexity
The time complexity of this optimized version using a priority queue is O(E log V), where E is the number of edges and V is the number of vertices. This is because:
This is a significant improvement over the O(n^2) complexity with the adjacency matrix, making this approach much more efficient for larger graphs.
Pros:
Cons:
Also Read: Heap Sort in Data Structures: Usability and Performance
In many real-world applications, you may only need to find the shortest path from a source node to a single destination vertex rather than all nodes in the graph. Modifying Dijkstra’s Algorithm to stop once the destination node is reached can significantly improve performance, especially in large graphs where calculating paths to all nodes is unnecessary.
This optimized approach focuses on terminating the algorithm early, making it more efficient for specific use cases like route planning or network analysis.
Step-by-Step Explanation
1. Initialize the Graph: Start by setting up the graph and initializing the distance array to infinity, with the distance to the starting node set to 0.
2. Priority Queue: Use a priority queue (min-heap) to select the node with the smallest tentative distance.
3. Process Nodes: Extract nodes from the priority queue, update distances to their neighbors, and push these neighbors back into the queue if a shorter path is found.
4. Early Termination: As soon as the destination node is reached, stop further processing. This avoids unnecessary computations for nodes that won’t be part of the shortest path.
5. Repeat: The algorithm continues until the destination node is reached or all reachable nodes have been processed.
Code Example
import heapq
def dijkstra_single_destination(adj_list, start_node, destination_node):
n = len(adj_list)
dist = [float('inf')] * n
dist[start_node] = 0
visited = [False] * n
min_heap = [(0, start_node)] # (distance, node)
while min_heap:
current_dist, current_node = heapq.heappop(min_heap)
if current_node == destination_node:
break # Stop as soon as we reach the destination node
if visited[current_node]:
continue
visited[current_node] = True
for neighbor, weight in adj_list[current_node]:
if visited[neighbor]:
continue
new_dist = current_dist + weight
if new_dist < dist[neighbor]:
dist[neighbor] = new_dist
heapq.heappush(min_heap, (new_dist, neighbor))
return dist[destination_node]
# Example graph represented as an adjacency list
graph = [ [(1, 5), (4, 10)], # Node 0
[(0, 5), (2, 3)], # Node 1
[(1, 3), (3, 1)], # Node 2
[(2, 1), (4, 2)], # Node 3
[(0, 10), (3, 2)] # Node 4
]
# Running Dijkstra's Algorithm from node 0 to node 3
start_node = 0
destination_node = 3
distance = dijkstra_single_destination(graph, start_node, destination_node)
print(f"Shortest distance from node {start_node} to node {destination_node}: {distance}")
Output:
Shortest distance from node 0 to node 3: 7
Explanation:
Time Complexity
The time complexity for this approach remains O(E log V), as the priority queue still needs to handle edge updates, and the graph is processed through the min-heap.
By terminating early when the destination is found, the algorithm processes fewer nodes. This can significantly improve practical runtime in many scenarios, especially when the destination is far from the source.
Pros:
Cons:
Selecting the right approach can significantly improve both performance and computational efficiency depending on the problem at hand—whether you're working with dense graphs, large-scale datasets, or specific destination queries.
Also Read: Top 14 Most Common Data Mining Algorithms You Should Know
With these various techniques in hand, let’s now look at how Dijkstra’s Algorithm is put to use in real-world applications.
Industries like telecommunications, logistics, and robotics rely on Dijkstra’s shortest path algorithm to optimize everything from network traffic to vehicle routes and robotic movement. Here’s how it’s applied across different sectors.
Industry |
Application |
Example |
Telecommunications | Ensuring data packets travel the most efficient path across complex networks. | Used by internet providers to route data efficiently through large networks, minimizing delays. |
Logistics | Finding the quickest routes for delivery vehicles or shipments. | Companies like UPS or FedEx use Dijkstra’s algorithm to optimize delivery routes, saving time and fuel costs. |
Robotics | Enabling robots to navigate efficiently in dynamic environments. | In autonomous vehicles and drones, Dijkstra’s algorithm helps plot the best paths while avoiding obstacles. |
Transportation | Calculating the shortest travel times for users. | GPS systems like Google Maps and Waze use Dijkstra's algorithm to suggest the quickest routes for drivers. |
Project Management | Finding the optimal sequence of tasks to minimize project time. | In project management software, Dijkstra’s algorithm helps determine the most efficient task dependencies. |
Whether it’s minimizing delivery times or routing data through vast networks, this algorithm plays a critical role in real-world applications.
Also Read: 48 Software Engineering Projects in 2025 With Source Code
Now that we’ve seen Dijkstra’s Algorithm in action let’s break down its strengths and limitations to know when it’s most effective.
Dijkstra’s Algorithm is a powerful tool for finding the shortest path, but like any algorithm, it has both strengths and limitations. Below is a breakdown of where it excels, where it may fall short, and how you can overcome its shortcomings.
Strengths |
Limitations |
Workarounds |
Efficiency in dense graphs: Dijkstra’s Algorithm excels in graphs with many edges, as it finds the shortest path in O(E log V) time with a priority queue. | Inefficient for large, sparse graphs: The algorithm can be slow for graphs with fewer edges, as it may still process a lot of unnecessary nodes. | Use A Search* or Bellman-Ford Algorithm for sparse graphs or cases with negative weights. |
Simplicity in implementation: It’s straightforward to implement using adjacency matrices or lists, making it an excellent starting point for pathfinding problems. | Space complexity: Storing the graph as an adjacency matrix takes up O(n^2) space, which is inefficient for large graphs. | Switch to an adjacency list to reduce space usage, especially for sparse graphs. |
Widely applicable: Dijkstra’s Algorithm is useful in navigation systems, network routing, and robotic path planning, where finding the shortest route is crucial. | Doesn’t handle negative weights: The algorithm doesn’t work if the graph has edges with negative weights. | Use Bellman-Ford Algorithm for graphs with negative edge weights, or apply a modified Dijkstra's approach with constraint handling. |
Optimal for single-source shortest path: It’s ideal when you only need the shortest path from one source to all other nodes. | Not ideal for multiple destination queries: For multiple destinations, recalculating paths for each destination can be inefficient. | Use Floyd-Warshall for frequent all-pairs queries or modify it to stop early for single-destination searches. |
Dijkstra’s Algorithm remains one of the most essential tools for solving shortest path problems. However, as with any algorithm, it’s important to recognize its limitations and understand when to choose alternative approaches for maximum efficiency.
With a global network of over 10 million learners, upGrad offers industry-focused courses that help both beginners and experienced professionals master key concepts in computer science.
These courses offer hands-on experience, bridging theory with real-world problem-solving.
Here are some of the top recommended courses:
Struggling to choose the right career path? Consult upGrad’s expert counselors or visit an offline center to find a course that aligns with your goals!
Boost your career with our popular Software Engineering courses, offering hands-on training and expert guidance to turn you into a skilled software developer.
Master in-demand Software Development skills like coding, system design, DevOps, and agile methodologies to excel in today’s competitive tech industry.
Stay informed with our widely-read Software Development articles, covering everything from coding techniques to the latest advancements in software engineering.
900 articles published
Get Free Consultation
By submitting, I accept the T&C and
Privacy Policy
India’s #1 Tech University
Executive PG Certification in AI-Powered Full Stack Development
77%
seats filled
Top Resources