You want to learn about Dijkstra’s Algorithm—one of the most popular shortest-path algorithms for weighted, non-negative edge weight graphs, right? It efficiently finds the shortest path from a single source node to all other nodes in the graph, making it essential for applications like GPS navigation, network routing, and resource allocation. Unlike DFS/BFS (which work for unweighted graphs), Dijkstra’s Algorithm accounts for edge weights to compute optimal paths.
I. Core Principles of Dijkstra’s Algorithm
Dijkstra’s Algorithm follows a greedy approach combined with a priority queue (min-heap) to always select the node with the currently known shortest distance from the source. Here’s the step-by-step workflow:
- Initialize Distances: Set the distance from the source node to itself as
0, and the distance to all other nodes asinfinity(a very large number). - Priority Queue Setup: Use a min-heap to store nodes to process, starting with the source node (distance = 0).
- Process Nodes: While the priority queue is not empty:
- Extract the node
uwith the smallest current distance from the heap. - For each neighbor
vofu, calculate the tentative distance tovviau(i.e.,distance[u] + weight(u, v)). - If the tentative distance is smaller than the known distance to
v, updatedistance[v]and addvto the priority queue (even if it’s already there—duplicate entries are handled by checking distances later).
- Extract the node
- Terminate: When the queue is empty, the
distancearray holds the shortest path from the source to all other nodes.
Key Notes
- Non-Negative Weights: Critical for correctness—if the graph has negative edge weights, Dijkstra’s Algorithm fails (use the Bellman-Ford Algorithm instead).
- Priority Queue (Min-Heap): Ensures we always process the node with the shortest known path first (the greedy choice).
- Visited Tracking: Not strictly required (duplicate heap entries are ignored if a shorter path is already found), but can optimize performance by skipping nodes that have already been processed.
II. Complete Implementation Code (Python)
Below are two implementations of Dijkstra’s Algorithm:
- Basic Version: Uses a min-heap with adjacency list representation (works for small to medium graphs).
- Optimized Version: Adds a visited set to avoid reprocessing nodes (faster for large graphs).
We also include a path-reconstruction feature to retrieve the actual shortest path (not just distances).
python
运行
import heapq
def dijkstra_basic(graph, source):
"""
Basic Dijkstra's Algorithm (min-heap, no visited set)
:param graph: Adjacency list (dict: node -> list of (neighbor, weight))
:param source: Starting node
:return: (distances, predecessors) - distances from source to all nodes, and predecessors for path reconstruction
"""
# Initialize distances: infinity for all nodes except source (0)
distances = {node: float('inf') for node in graph}
distances[source] = 0
# Predecessors dict to reconstruct paths (node -> previous node in shortest path)
predecessors = {node: None for node in graph}
# Min-heap: (current distance, node) - starts with source
heap = []
heapq.heappush(heap, (0, source))
while heap:
current_dist, u = heapq.heappop(heap)
# Skip if a shorter path to u has already been found (duplicate heap entry)
if current_dist > distances[u]:
continue
# Explore all neighbors of u
for v, weight in graph[u]:
tentative_dist = current_dist + weight
# Update distance if tentative path is shorter
if tentative_dist < distances[v]:
distances[v] = tentative_dist
predecessors[v] = u
heapq.heappush(heap, (tentative_dist, v))
return distances, predecessors
def dijkstra_optimized(graph, source):
"""
Optimized Dijkstra's Algorithm (min-heap + visited set)
:param graph: Adjacency list
:param source: Starting node
:return: (distances, predecessors)
"""
distances = {node: float('inf') for node in graph}
distances[source] = 0
predecessors = {node: None for node in graph}
heap = []
heapq.heappush(heap, (0, source))
visited = set() # Track processed nodes to avoid rework
while heap:
current_dist, u = heapq.heappop(heap)
# Skip if u is already processed
if u in visited:
continue
visited.add(u)
# Explore neighbors (only process unvisited nodes for optimization)
for v, weight in graph[u]:
if v not in visited:
tentative_dist = current_dist + weight
if tentative_dist < distances[v]:
distances[v] = tentative_dist
predecessors[v] = u
heapq.heappush(heap, (tentative_dist, v))
return distances, predecessors
def reconstruct_path(predecessors, source, target):
"""
Reconstruct the shortest path from source to target using predecessors dict
:param predecessors: Dict from dijkstra functions
:param source: Starting node
:param target: End node
:return: List of nodes in the shortest path (or empty list if no path exists)
"""
path = []
current = target
# Trace back from target to source using predecessors
while current is not None:
path.append(current)
current = predecessors[current]
# Avoid infinite loop if there's no path (cycle)
if len(path) > len(predecessors) + 1:
return []
# Reverse to get path from source to target
path.reverse()
# Check if path is valid (starts with source)
return path if path[0] == source else []
# Test Case
if __name__ == "__main__":
# Adjacency list representation of a weighted graph
# Format: node -> [(neighbor, weight), ...]
graph = {
'A': [('B', 4), ('C', 1)],
'B': [('A', 4), ('C', 2), ('D', 5)],
'C': [('A', 1), ('B', 2), ('D', 1)],
'D': [('B', 5), ('C', 1)]
}
# Run basic Dijkstra's from source 'A'
dist_basic, pred_basic = dijkstra_basic(graph, 'A')
print("Basic Dijkstra's - Distances from A:")
for node, dist in dist_basic.items():
print(f" {node}: {dist}") # Output: A:0, B:3, C:1, D:2
# Reconstruct path from A to D
path_a_to_d = reconstruct_path(pred_basic, 'A', 'D')
print(f"\nShortest path from A to D: {path_a_to_d}") # Output: ['A', 'C', 'D']
# Run optimized Dijkstra's from source 'A'
dist_optimized, pred_optimized = dijkstra_optimized(graph, 'A')
print("\nOptimized Dijkstra's - Distances from A:")
for node, dist in dist_optimized.items():
print(f" {node}: {dist}") # Same as basic version
III. Key Code Explanations
1. Graph Representation
- Uses an adjacency list (dictionary) where each key is a node, and the value is a list of tuples
(neighbor, weight)—the most efficient way to represent sparse graphs (most real-world graphs are sparse).
2. Distance Initialization
float('inf')(infinity) represents the initial unknown distance from the source to all other nodes. Only the source node has a distance of0.
3. Min-Heap Operations
heapq.heappush(heap, (distance, node)): Adds a node to the heap with its current known distance.heapq.heappop(heap): Extracts the node with the smallest distance (the greedy choice for processing).
4. Path Reconstruction
- The
predecessorsdictionary tracks the previous node in the shortest path for each node. Thereconstruct_pathfunction traces back from the target to the source and reverses the result to get the forward path.
5. Optimized Version (Visited Set)
- The
visitedset skips nodes that have already been processed (since their shortest path is already found). This reduces the number of heap operations and speeds up the algorithm for large graphs.
IV. Algorithm Performance Analysis
| Metric | Result | Explanation |
|---|---|---|
| Time Complexity | O((V + E) log V) | – V: Number of vertices (nodes).- E: Number of edges.- Each heap operation (push/pop) takes O(log V) time.- Each node/edge is processed once (O(V + E)), with O(log V) per heap operation. |
| Space Complexity | O(V) | – O(V) for the distance and predecessors dictionaries.- O(V) for the min-heap (worst case: all nodes are in the heap at once). |
| Restrictions | Only works for weighted graphs with non-negative edge weights. Fails for graphs with negative weights or negative cycles. |
Why Non-Negative Weights?
Dijkstra’s Algorithm makes a greedy choice: once a node is processed (extracted from the heap), its shortest path is considered final. If there’s a negative edge weight, a later path to the node could be shorter—invalidating the greedy choice. For example:
- Graph:
A → B (weight 5),A → C (weight 1),C → B (weight -3) - Dijkstra’s would set
B’s distance to 5 (via A) and mark it as processed, but the actual shortest path isA→C→B(distance 1 – 3 = -2).
V. Dijkstra’s Algorithm vs. BFS vs. Bellman-Ford
| Feature | Dijkstra’s Algorithm | BFS (Breadth-First Search) | Bellman-Ford Algorithm |
|---|---|---|---|
| Graph Type | Weighted (non-negative) | Unweighted | Weighted (negative weights allowed) |
| Shortest Path | Single source to all nodes | Single source to all nodes (unweighted) | Single source to all nodes (handles negative weights) |
| Time Complexity | O((V + E) log V) | O(V + E) | O(V * E) |
| Space Complexity | O(V) | O(V) | O(V) |
| Use Case | GPS navigation, network routing | Maze solving, unweighted pathfinding | Detecting negative cycles, graphs with negative weights |
VI. Practical Applications
- GPS and Navigation Systems: Computes the shortest/ fastest route between two locations (e.g., Google Maps, Waze). Edge weights represent distance, time, or cost.
- Network Routing Protocols: Used in protocols like OSPF (Open Shortest Path First) to find the shortest path between routers in a computer network.
- Resource Allocation: Optimizes the allocation of resources (e.g., bandwidth, memory) in distributed systems by finding the least-cost path for data transfer.
- Robotics: Plans the shortest path for robots to move from a start to a target position in a weighted environment (e.g., avoiding obstacles with higher weights).
- Flight Scheduling: Finds the cheapest/ shortest flight routes between cities (edge weights represent fare or travel time).
Summary
Practical uses: GPS navigation, network routing, resource allocation, and robotics path planning.
Dijkstra’s Algorithm is a greedy, single-source shortest-path algorithm for weighted graphs with non-negative edge weights.
Core steps: Initialize distances → use a min-heap to process nodes greedily → update distances for neighbors → reconstruct paths (optional).
Time complexity: O((V + E) log V) (efficient for sparse graphs); space complexity: O(V).
Key restriction: Cannot handle negative edge weights (use Bellman-Ford instead).
- High-Performance Waterproof Solar Connectors
- Durable IP68 Waterproof Solar Connectors for Outdoor Use
- High-Quality Tinned Copper Material for Durability
- High-Quality Tinned Copper Material for Long Service Life
- Y Branch Parallel Solar Connector for Enhanced Power
- 10AWG Tinned Copper Solar Battery Cables
- NEMA 5-15P to Powercon Extension Cable Overview
- Dual Port USB 3.0 Adapter for Optimal Speed
- 4-Pin XLR Connector: Reliable Audio Transmission
- 4mm Banana to 2mm Pin Connector: Your Audio Solution
- 12GB/s Mini SAS to U.2 NVMe Cable for Fast Data Transfer
- CAB-STK-E Stacking Cable: 40Gbps Performance
- High-Performance CAB-STK-E Stacking Cable Explained
- Best 10M OS2 LC to LC Fiber Patch Cable for Data Centers
- Mini SAS HD Cable: Boost Data Transfer at 12 Gbps
- Multi Rate SFP+: Enhance Your Network Speed
- Best 6.35mm to MIDI Din Cable for Clear Sound
- 15 Pin SATA Power Splitter: Solutions for Your Device Needs
- 9-Pin S-Video Cable: Enhance Your Viewing Experience
- USB 9-Pin to Standard USB 2.0 Adapter: Easy Connection
- 3 Pin to 4 Pin Fan Adapter: Optimize Your PC Cooling
- S-Video to RCA Cable: High-Definition Connections Made Easy
- 6.35mm TS Extension Cable: High-Quality Sound Solution
- BlackBerry Curve 9360: Key Features and Specs






















Leave a comment