Bài 13.2 - Phân tích độ phức tạp Dijkstra trong
Free
Khóa học Python từ Cơ bản đến Nâng cao
Chương 1: Làm quen với Python + Ôn tập I/O, biến, kiểu dữ liệu
Chương 2: Câu lệnh rẽ nhánh, vòng lặp, hàm
Chương 3: Xử lý chuỗi và danh sách nâng cao
Chương 4: Bài kiểm tra Python cơ bản + sửa bài
Chương 5: Duyệt mảng, tìm max/min, đếm
Chương 6: Thuật toán sắp xếp
Chương 7: Prefix Sum + Two Pointers
Chương 8: Backtracking cơ bản
Chương 9: Ôn tập thuật toán cơ bản + kiểm tra
Chương 10: Dynamic Programming cơ bản
Chương 11: Đệ quy và DP nâng cao
Chương 12: Đồ thị cơ bản – DFS, BFS
Chương 13: Đồ thị nâng cao – Dijkstra + Topo sort
Chương 14: Cây – Tree traversal + LCA
Chương 15: Bitmask – Kỹ thuật đại số
Chương 16: Số học + Modular Arithmetic
Chương 17: Class
Chương 18: File và Exception

Bài 13.2 - Phân tích độ phức tạp Dijkstra trong Python
Sau khi đã học cách cài đặt thuật toán Dijkstra với heapq
, bây giờ chúng ta sẽ đi sâu vào phân tích độ phức tạp thời gian và bộ nhớ của thuật toán này, để hiểu vì sao nó lại hiệu quả và khi nào nó phù hợp.
Tóm tắt lại thuật toán Dijkstra
- Áp dụng cho đồ thị có trọng số không âm
- Tìm khoảng cách ngắn nhất từ một đỉnh nguồn đến tất cả các đỉnh khác
- Sử dụng hàng đợi ưu tiên (min-heap) để ưu tiên đỉnh có khoảng cách nhỏ nhất
Cài đặt nhắc lại bằng heapq
import heapq
def dijkstra(graph, start):
distances = {node: float('inf') for node in graph}
distances[start] = 0
heap = [(0, start)]
while heap:
current_dist, current_node = heapq.heappop(heap)
if current_dist > distances[current_node]:
continue
for neighbor, weight in graph[current_node]:
distance = current_dist + weight
if distance < distances[neighbor]:
distances[neighbor] = distance
heapq.heappush(heap, (distance, neighbor))
return distances
Các yếu tố ảnh hưởng đến độ phức tạp
V
: số đỉnh trong đồ thịE
: số cạnh trong đồ thịheapq
là min-heap – mất O(log V) cho mỗi thao tác push và pop
Phân tích độ phức tạp thời gian
Thành phần | Độ phức tạp |
---|---|
Khởi tạo khoảng cách | O(V) |
Mỗi đỉnh được đưa vào heap 1 lần duy nhất | O(V × log V) |
Duyệt qua các cạnh | O(E × log V) |
Tổng thể: O((V + E) × log V)
Tức là với đồ thị thưa (sparse), thuật toán chạy rất hiệu quả.
So sánh với cài đặt không dùng heap
Nếu bạn dùng danh sách thường để tìm đỉnh gần nhất:
def get_min_node(distances, visited):
min_node = None
min_dist = float('inf')
for node in distances:
if node not in visited and distances[node] < min_dist:
min_dist = distances[node]
min_node = node
return min_node
Độ phức tạp sẽ là: O(V²)
Vì mỗi lần bạn phải quét toàn bộ danh sách để chọn đỉnh gần nhất.
Ví dụ minh hoạ tốc độ
Đồ thị 1: Nhỏ (4 đỉnh)
graph = {
'A': [('B', 1), ('C', 4)],
'B': [('C', 2), ('D', 5)],
'C': [('D', 1)],
'D': []
}
Chạy Dijkstra bằng heapq
sẽ chỉ mất vài ms.
Đồ thị 2: Lớn (1000 đỉnh, mỗi đỉnh nối 2 đỉnh kế tiếp)
graph = {i: [(i + 1, 1), (i + 2, 1)] for i in range(998)}
graph[998] = [(999, 1)]
graph[999] = []
# Gọi Dijkstra
dijkstra(graph, 0)
- Với heap: chạy nhanh, mượt
- Nếu không dùng heap: cực kỳ chậm
Phân tích bộ nhớ
Thành phần | Kích thước |
---|---|
distances |
O(V) |
heap |
Tối đa O(V) phần tử |
graph |
O(V + E) |
Khi nào không nên dùng Dijkstra?
- Đồ thị có trọng số âm → dùng Bellman-Ford
- Cần tìm đường đi tốt nhất tới một đích duy nhất → có thể dùng A*
Tổng kết
- Thuật toán Dijkstra khi dùng với
heapq
có độ phức tạp tối ưu là O((V + E) × log V) - Cần hiểu rõ heap giúp tối ưu hoá phần chọn đỉnh gần nhất
- Cài đặt đơn giản nhưng cực kỳ hiệu quả cho đồ thị lớn, không trọng số âm
Khóa học liên quan

3300000
4500000
Học Ngay
Comments