Thuật toán Dijkstra trong Python & C++ (Thí dụ)

⚡ Tóm tắt thông minh

Thuật toán Dijkstra tính toán đường đi ngắn nhất từ ​​một đỉnh nguồn duy nhất đến mọi đỉnh khác trong một đồ thị có trọng số với các cạnh không âm. Phương pháp tham lam này là nền tảng của... Google Định tuyến bản đồ, định tuyến IP OSPF và vô số trường hợp sử dụng đường đi ngắn nhất trong mạng.

  • 🎯 Ý tưởng cốt lõi: Thuật toán Dijkstra mở rộng một cách tham lam đỉnh chưa được thăm gần nhất, cập nhật khoảng cách lân cận cho đến khi mọi nút có thể đến được đều có chi phí ngắn nhất thực sự từ nguồn.
  • 🔄 So với BFS và DFS: Thuật toán BFS và DFS tìm bất kỳ đường đi nào mà không cần xét đến trọng số cạnh, trong khi thuật toán Dijkstra tối thiểu hóa tổng chi phí trên các cạnh có trọng số.
  • 🧭 Ví dụ từng bước: Một đồ thị có trọng số 7 đỉnh được xử lý cho thấy khoảng cách được cập nhật lặp đi lặp lại như thế nào và đường đi 1-2-6-7 thắng với chi phí là 7.
  • 💻 Phạm vi ngôn ngữ: Cả hai C++ và Python Các cách triển khai minh họa phiên bản ma trận kề với hàm lựa chọn khoảng cách tối thiểu.
  • ⚠️ hạn chế: Thuật toán Dijkstra không hoạt động với trọng số cạnh âm vì một nút đã được hoàn tất sẽ không bao giờ được xem xét lại; hãy sử dụng thuật toán Bellman-Ford cho các đồ thị có cạnh âm.
  • 📊 Phức tạp: Phiên bản mảng đơn giản chạy trong thời gian và không gian O(V²); hàng đợi ưu tiên giảm thời gian xuống O(E log V) đối với đồ thị thưa.

Thuật toán tìm đường đi ngắn nhất của Dijkstra

Đường đi ngắn nhất hay khoảng cách ngắn nhất là gì?

Đường đi từ đỉnh nguồn đến đỉnh đích có chi phí nhỏ nhất được gọi là đường đi ngắn nhất hoặc khoảng cách ngắn nhất. Trong lý thuyết đồ thị, có thể có nhiều tuyến đường từ nguồn đến đích. Trong số các tuyến đường này, nếu có một tuyến đường có chi phí nhỏ nhất, ta gọi đó là đường đi ngắn nhất.

Ở đây, "chi phí" có nghĩa là số lượng nút trong tuyến đường hoặc tổng chi phí trên mỗi cạnh. Một đường đi có thể có một hoặc nhiều cạnh. Kết nối giữa hai đỉnh được gọi là "cạnh". Có nhiều loại thuật toán tìm đường đi ngắn nhất, chẳng hạn như thuật toán Dijkstra và thuật toán Bellman-Ford.

Ở đây, chúng ta sẽ thảo luận về thuật toán Dijkstra. Hãy xem xét đồ thị có trọng số sau:

Đồ thị có trọng số vô hướng

Đồ thị có trọng số vô hướng

  • Thuật ngữ “có trọng số” (weighted) biểu thị chi phí di chuyển từ nút này sang nút khác. Ví dụ, di chuyển từ nút 1 sang nút 2, chi phí hay trọng số là 1.
  • Đường đi giữa nút 1 và nút 2 được gọi là cạnh.
  • "Không định hướng" có nghĩa là bạn có thể di chuyển từ nút này sang nút khác và quay lại nút trước đó. Vì vậy, nếu chúng ta cố gắng tìm tất cả các tuyến đường từ nút 1 đến nút 7, chúng sẽ là:
Tuyến đường hoặc Đường dẫnChi phí
1-2-6-7(1+3+3) = 7
1-2-3-7(1+9+1) = 11
1-3-7(7+1) = 8
1-4-5-7(6+2+5) = 13

Trong bốn tuyến đường này, ta thấy tuyến đường đầu tiên có chi phí là 7. Vì vậy, đây là con đường ngắn nhất xét về chi phí.

Con đường ngắn nhất

Con đường ngắn nhất

Thuật toán Dijkstra hoạt động như thế nào

Thuật toán Dijkstra có thể tìm khoảng cách ngắn nhất trong cả đồ thị có hướng và không hướng có trọng số. Thuật toán này được gọi là tham lam vì nó luôn chọn nút ngắn nhất hoặc gần nhất từ ​​gốc tọa độ. Thuật ngữ “tham lam” có nghĩa là trong một tập hợp các kết quả, thuật toán sẽ chọn kết quả tốt nhất.

Ở đây, chúng ta đang cố gắng tìm đường đi ngắn nhất trong số tất cả các tuyến đường khác. Vì vậy, thuật toán Dijkstra tìm tất cả các đường đi ngắn nhất từ ​​một nút nguồn duy nhất. Kết quả là, nó hoạt động giống như một... thuật toán tham lam.

Trong phần "ví dụ" bên dưới, bạn sẽ thấy cách thực hiện từng bước. Nó hoạt động như sau:

Bước 1) Khởi tạo nút đầu tiên với chi phí bằng 0 và các nút còn lại với chi phí vô hạn.
Bước 2) Duy trì một mảng hoặc danh sách để lưu trữ track trong số các nút đã được truy cập.
Bước 3) Cập nhật chi phí nút bằng chi phí tối thiểu. Điều này có thể được thực hiện bằng cách so sánh chi phí hiện tại với chi phí đường dẫn (được minh họa trong phần ví dụ).
Bước 4) Tiếp tục bước 3 cho đến khi tất cả các nút được duyệt qua.

Sau khi hoàn thành tất cả các bước này, chúng ta sẽ tìm ra đường đi có chi phí tối thiểu từ nguồn đến đích.

Sự khác biệt giữa Dijkstra và BFS, DFS

Sự khác biệt chính giữa thuật toán Dijkstra và BFS-DFS là Dijkstra là thuật toán tìm đường đi ngắn nhất, trong khi BFS và DFS là các thuật toán tìm đường đi tổng quát. Trong trường hợp tổng quát, BFS và DFS không xem xét chi phí cạnh khi tìm đường đi. Do đó, các thuật toán này không thể đảm bảo đường đi ngắn nhất.

Minh họa cách thức hoạt động của thuật toán BFS trên lưới 2D.

Minh họa lưới 2D BFS

Thuật toán, hiển thị bản trình diễn BFS

Phần trình diễn này chỉ ra rằng BFS chỉ tìm thấy đường dẫn. Tuy nhiên, nó không quan tâm đến trọng lượng của đường đi. BFS (Tìm kiếm theo chiều rộng đầu tiên) giả định rằng việc di chuyển từ nút này sang nút khác sẽ chỉ tốn 1.

Chúng ta hãy xem một ví dụ về đồ thị:

Ví dụ đồ thị minh họa dạng lưới 2D

Ở đây, thuật toán BFS tìm đường đi ở cấp độ 2. BFS duyệt đồ thị theo thứ tự cấp độ. Vì vậy, nó di chuyển như sau:

Bước 1) Bắt đầu từ nút “1” và đi qua tất cả các nút liền kề 2, 3, 4.

Bước 2) Đánh dấu các nút 2, 3, 4 là cấp độ 1 và thăm các nút liền kề của chúng. Nó sẽ tiếp tục khám phá tất cả các nút liền kề cho đến khi đến nút đích.

Về mặt DFS, nó sẽ đi qua đường dẫn từ 1 đến 7 như sau:

  • 1→2→3→7 (Chi phí gốc 10, Chi phí DFS 3)
  • 1→2→6→7 (Chi phí gốc 7, Chi phí DFS 3)
  • 1→3→7 (Chi phí ban đầu 8, Chi phí DFS 2)
  • 1→4→5→7 (Chi phí gốc 13, Chi phí DFS 3)

Như chúng ta thấy, DFS tính toán chi phí đường đi dựa trên số lượng cạnh. DFS thực hiện như sau:

  • DFS có thể tìm đường dẫn từ nguồn (đỉnh bắt đầu) đến đích.
  • Nó không thể đảm bảo liệu đường dẫn được phát hiện từ nút nguồn đến đích có phải là đường dẫn ngắn nhất hay không.

Tuy nhiên, xét về thuật toán Dijkstra, nó chọn các cạnh dựa trên chi phí của chúng. Là một thuật toán tham lam, nó sẽ chọn các đường dẫn có chi phí tối thiểu.

Ví dụ về thuật toán Dijkstra

Thuật toán Dijkstra sử dụng chi phí hoặc trọng số để tính tổng chi phí của đường đi.

Ví dụ về thuật toán Dijkstra

Mục tiêu của Thuật toán Dijkstra là giảm thiểu tổng chi phí hoặc trọng lượng này. Trong ví dụ hiển thị ở trên, chúng tôi tìm đường đi tốt nhất từ ​​nút 1 đến nút 7, sau đó tính toán tất cả chi phí.

Trong thuật toán Dijkstra, nó sẽ tìm đường đi ngắn nhất bằng cách tính toán trọng số. Nó sẽ không tìm kiếm tất cả các đường đi có thể. Chúng ta hãy minh họa thuật toán Dijkstra bằng một ví dụ. Ví dụ, bạn được yêu cầu tìm đường đi ngắn nhất từ ​​nút 1 đến nút 7.

Đối với quá trình này, các bước được đưa ra dưới đây:

Bước 1) Khởi tạo chi phí nút ban đầu bằng 0. Gán “Thông tin” đến các nút còn lại. Điều đó có nghĩa là không có đường dẫn nào tồn tại giữa nút nguồn và nút đó, hoặc đường dẫn đó chưa được đi qua.

Khởi tạo thuật toán Dijkstra

Bước 2) Khi bạn chọn nút 1, nó sẽ được đánh dấu là đã được thăm. Sau đó, cập nhật tất cả các nút lân cận của nút 1. 2, 3, 4 là các nút lân cận của nút 1.

Trong khi cập nhật chi phí, chúng ta cần thực hiện theo quy trình dưới đây:

Quy trình cập nhật thuật toán Dijkstra

Chúng ta có thể cập nhật chi phí của mỗi nút bằng công thức trên. Ví dụ, chúng ta đang ở nút 1 và cần cập nhật chi phí của các nút liền kề 2, 3, 4. Sau khi cập nhật, chi phí sẽ trông như thế này:

Thuật toán Dijkstra sau lần cập nhật đầu tiên

Bước 3) Đối với nút “2”, các nút lân cận là 6 và 3. Chúng ta cập nhật chi phí tại “6” bằng cách so sánh vô cực (giá trị hiện tại) với chi phí của nút 2 cộng với chi phí đường đi từ 2 đến 6. Nói một cách đơn giản, nút “6” sẽ có chi phí là 1+3 hoặc 4.

Thuật toán Dijkstra cập nhật nút 6

Nút 3 là hàng xóm của nút 2. Tuy nhiên, chúng tôi đã tính chi phí của nó ở bước trước là 7. Bây giờ, nếu đường dẫn của chúng tôi là 1-2-3, nút 3 sẽ có chi phí là 10. Đường dẫn 1-2- 3 sẽ có giá 10, trong khi 1 đến 3 sẽ có giá 7.

Bước 4) Đối với nút 3, nút lân cận là 7. Vì vậy, bằng cách so sánh giá trị hiện tại của nút 7 với chi phí đường đi (7+1) hoặc 8, ta sẽ cập nhật chi phí của nút 7. Đó là 8. Vì vậy, ta tìm một đường đi từ nút 1 đến nút 7, và đó là 1→3→7. Chi phí là 8.

Bước 5) Đối với nút 4, chúng ta sẽ cập nhật chi phí của nút liền kề tương ứng. Vì vậy, nút “5” sẽ có chi phí được cập nhật là 8. Sau bước 4 và 5, kết quả sẽ trông như thế này:

Thuật toán Dijkstra sau bước 4 5

Hiện tại, đường đi 1-3-7 có chi phí là 8 (trước đây). Nút “7” không được đánh dấu là đã ghé thăm vì ta có thể đến nút “7” từ nút “6”. Đường đi “1-2-6” có chi phí là 4. Vì vậy, đường đi 1-2-6-7 sẽ có chi phí là 7.

Vì 7 < 8, đường đi ngắn nhất từ ​​đỉnh nguồn “1” đến đỉnh đích “7” sẽ là 1-2-6-7, và chi phí là 7. Trước đó là 1-3-7, và chi phí là 8. Vì vậy, đồ thị cuối cùng sẽ có dạng như sau:

Đồ thị cuối cùng của thuật toán Dijkstra

Cạnh được đánh dấu bằng một đường màu đen là đường đi ngắn nhất của chúng ta từ 1 đến 7 và chúng ta sẽ phải trả 7.

Biệt danh Code Thuật toán Dijkstra

Đây là mã giả của thuật toán Dijkstra:

Dijkstra(G, S):
  for each vertex V in G
    distance[V] <- Infinity
    previous[V] <- NULL
    if V does not equal S, then,
      (priority queue) Q.push(V)
  distance[S] = 0
  While Q is not empty
    U <- Extract the MIN from Q
    For each unvisited adjacent V of U
      TotalDistance <- distance[U] + edge_cost(U, V)
      if TotalDistance is less than distance[V], then
        distance[V] <- TotalDistance
        previous[V] <- U
  return distance, previous

C++ Triển khai thuật toán Dijkstra

Để thực hiện thuật toán Dijkstra bằng cách sử dụng C++Đây là đoạn mã:

#include <bits/stdc++.h>
using namespace std;
#define size 7
int minimumDistance(int distance[], bool visited[]) {
  int min = INT_MAX;
  int min_index = INT_MAX;
  for (int i = 0; i < size; i++) {
    if (!visited[i] && distance[i] <= min) {
      min = distance[i];
      min_index = i;
    }
  }
  return min_index;
}
void printParentPath(int parent[], int i) {
  if (parent[i] == -1) {
    return;
  }
  printParentPath(parent, parent[i]);
  cout << i + 1 << " ";
}
void dijkstra(int graph[size][size], int source) {
  int distance[size];
  bool visited[size];
  int parent[size];
  for (int i = 0; i < size; i++) {
    parent[0] = -1;
    distance[i] = INT_MAX;
    visited[i] = false;
  }
  distance[source] = 0;
  for (int i = 0; i < size - 1; i++) {
    int U = minimumDistance(distance, visited);
    visited[U] = true;
    for (int j = 0; j < size; j++) {
      int curr_distance = distance[U] + graph[U][j];
      if (!visited[j] && graph[U][j] &&
          curr_distance < distance[j]) {
        parent[j] = U;
        distance[j] = curr_distance;
      }
    }
  }
  cout << "Vertex\t\tDistance\tPath" << endl;
  for (int i = 1; i < size; i++) {
    cout << source + 1 << "->" << i + 1 << "\t\t" << distance[i] << "\t\t"
         << source + 1 << " ";
    printParentPath(parent, i);
    cout << endl;
  }
}
int main() {
  int graph[size][size] = {{0, 1, 7, 6, 0, 0, 0}, {1, 0, 9, 0, 0, 3, 0},
                           {7, 9, 0, 0, 0, 0, 1}, {6, 0, 0, 0, 2, 0, 0},
                           {0, 0, 0, 2, 0, 0, 0}, {0, 3, 0, 0, 0, 0, 3},
                           {0, 0, 0, 0, 5, 3, 0}};
  dijkstra(graph, 0);
}

Đầu ra:

Vertex     Distance        Path

1->2           1             1 2
1->3           7             1 3
1->4           6             1 4
1->5           8             1 4 5
1->6           4             1 2 6
1->7           7             1 2 6 7

Python Triển khai thuật toán Dijkstra

Để thực hiện thuật toán Dijkstra bằng cách sử dụng PythonĐây là đoạn mã:

num_of_vertex = 7
def minimumDistance(distance, visited):
    _min = 1e11
    min_index = 1e11
    for i in range(num_of_vertex):
        if not visited[i] and distance[i] <= _min:
            _min = distance[i]
            min_index = i
    return min_index

def printParentNode(parent, i):
    if parent[i] == -1:
        return
    printParentNode(parent, parent[i])
    print("{} ".format(i + 1), end="")

def dijkstra(graph, src):
    distance = list()
    visited = list()
    parent = list()
    for i in range(num_of_vertex):
        parent.append(-1)
        distance.append(1e11)
        visited.append(False)
    distance[src] = 0
    for i in range(num_of_vertex - 1):
        U = minimumDistance(distance, visited)
        visited[U] = True
        for j in range(num_of_vertex):
            curr_distance = distance[U] + graph[U][j]
            if not visited[j] and graph[U][j] and curr_distance < distance[j]:
                parent[j] = U
                distance[j] = curr_distance
    print("Vertex\t\tDistance\tPath")
    for i in range(num_of_vertex):
        print("{}->{}\t\t{}\t\t{} ".format(src + 1, i + 1, distance[i], src + 1), end="")
        printParentNode(parent, i)
        print("")

graph = [
    [0, 1, 7, 6, 0, 0, 0],
    [1, 0, 9, 0, 0, 3, 0],
    [7, 9, 0, 0, 0, 0, 1],
    [6, 0, 0, 0, 2, 0, 0],
    [0, 0, 0, 2, 0, 0, 0],
    [0, 3, 0, 0, 0, 0, 3],
    [0, 0, 0, 0, 5, 3, 0]
]
dijkstra(graph, 0)

Đầu ra:

Vertex     Distance        Path

1->1           0              1
1->2           1              1 2
1->3           7              1 3
1->4           6              1 4
1->5           8              1 4 5
1->6           4              1 2 6
1->7           7              1 2 6 7

Ta có thể thấy rằng thuật toán tính toán khoảng cách ngắn nhất từ ​​nút nguồn.

Ứng dụng thuật toán Dijkstra

Thuật toán Dijkstra có rất nhiều ứng dụng. Trong số đó, nó được sử dụng rộng rãi trong lĩnh vực mạng máy tính. Dưới đây là một số ứng dụng thực tế của thuật toán Dijkstra:

Dijkstra trong Google Bản đồ: Thuật toán này là nền tảng để tìm đường đi ngắn nhất, như chúng ta có thể thấy từ đoạn mã đầu ra ở trên.

Ứng dụng thuật toán Dijkstra Google Maps

Google Ứng dụng này không sử dụng thuật toán Dijkstra đơn giản. Thay vào đó, nó sử dụng một phiên bản đã được sửa đổi. Khi bạn chọn điểm đến, nó sẽ hiển thị cho bạn nhiều đường dẫn khác nhau. Google Bản đồ. Trong số các tuyến đường này, một số được sắp xếp cho người dùng. Các tuyến đường này được chọn dựa trên "thời gian". Vì vậy, "thời gian" là chi phí cạnh cho tuyến đường ngắn nhất.

Thuật toán Dijkstra trong định tuyến IP: Định tuyến IP IP routing là thuật ngữ mạng. Nó mô tả cách gói dữ liệu của bạn được gửi đến người nhận thông qua các đường dẫn khác nhau. Các đường dẫn này bao gồm bộ định tuyến, máy chủ và các thiết bị khác. Trong định tuyến IP, có nhiều loại giao thức khác nhau.

Các giao thức này giúp bộ định tuyến tìm ra đường dẫn ngắn nhất để gửi dữ liệu. Một trong những tên giao thức đó là “OSPF (Open Shortest Path First)”. OSPF sử dụng thuật toán Dijkstra. Bộ định tuyến duy trì một bảng các tuyến đường. Mỗi bộ định tuyến chia sẻ bảng của mình với các bộ định tuyến lân cận. Sau khi nhận được bảng được cập nhật, chúng phải tính toán lại tất cả các đường dẫn. Tại thời điểm đó, bộ định tuyến sử dụng thuật toán Dijkstra.

Hạn chế của thuật toán Dijkstra

Thuật toán Dijkstra không thể đảm bảo tìm được đường đi ngắn nhất trong đồ thị có các cạnh âm. Thuật toán Dijkstra tuân theo các nguyên tắc sau:

  • Một đường đi ngắn nhất sẽ được đi từ nút này sang nút khác.
  • Khi đường đi ngắn nhất giữa hai nút được chọn, nó sẽ không được tính lại.

Ở đây, hãy chú ý hai ví dụ có cạnh âm.

Hạn chế của thuật toán Dijkstra: các cạnh âm

Trong biểu đồ bên trái, Đồ thị có ba đỉnh. Thuật toán Dijkstra sẽ chạy trên đồ thị như sau:

Bước 1) Đỉnh bắt đầu “1” sẽ được khởi tạo bằng XNUMX. Các nút khác sẽ có vô cùng.

Hạn chế của thuật toán Dijkstra bước 1

Bước 2) Đánh dấu nút “1” là nút đã được ghé thăm và đưa nó vào đường đi ngắn nhất.

Bước 3) Khoảng cách từ nút nguồn 1 đến các nút “2” và “3” được đặt là vô cực, vì đường đi ngắn nhất vẫn chưa được tính toán. Do đó, bất kỳ đường đi nào có chi phí nhỏ hơn vô cực sẽ được thêm vào đường đi ngắn nhất (phương pháp tham lam).

Bước 4) Cập nhật khoảng cách từ đỉnh nguồn “1” đến “2”. Trọng lượng hiện tại sẽ là 5 (5 < vô cực). Tương tự, cập nhật khoảng cách từ nút “1” đến “3” với trọng lượng là 3.

Hạn chế của thuật toán Dijkstra bước 4

Bước 5) Bây giờ, nếu ta kiểm tra khoảng cách ngắn nhất từ ​​nút “1”, ta thấy rằng 5 là khoảng cách ngắn nhất cho cạnh 1→2. Vì vậy, nút “2” sẽ được đánh dấu là đã được thăm. Tương tự, nút “3” cũng sẽ được đánh dấu là đã được thăm vì khoảng cách ngắn nhất là 3.

Tuy nhiên, nếu quan sát kỹ, ta thấy có một đường đi 1-3-2 chỉ tốn 2 chi phí. Nhưng thuật toán Dijkstra lại cho thấy khoảng cách ngắn nhất từ ​​nút “1” đến nút “2” là 5. Như vậy, thuật toán Dijkstra đã không tính toán được khoảng cách ngắn nhất một cách chính xác. Lý do là vì Dijkstra là một thuật toán tham lam. Do đó, một khi một nút đã được đánh dấu là đã thăm, nó sẽ không được xem xét lại, mặc dù có thể có một đường đi ngắn hơn. Vấn đề này chỉ xảy ra khi các cạnh có chi phí âm hoặc trọng số âm.

Thuật toán Dijkstra không thể tính toán đường đi ngắn nhất giữa hai nút trong trường hợp này. Do đó, thuật toán này có một số nhược điểm. Để giải quyết vấn đề cạnh âm này, một thuật toán khác được gọi là "Thuật toán Bellman-Ford" được sử dụng. Thuật toán đó có thể hoạt động với các cạnh âm.

Độ phức tạp của thuật toán Dijkstra

Việc triển khai ở trên sử dụng hai vòng lặp “for”. Các vòng lặp này chạy cho số đỉnh. Vì vậy, độ phức tạp về thời gian là O(V²)Ở đây, thuật ngữ “O” là một ký hiệu đưa ra giả định cho thuật toán Dijkstra.

Chúng ta có thể lưu trữ đồ thị bằng cách sử dụng "hàng đợi ưu tiên". Hàng đợi ưu tiên là một cấu trúc dữ liệu heap nhị phân. Nó sẽ hiệu quả hơn ma trận 2D. Một cạnh có chi phí tối thiểu sẽ có độ ưu tiên cao. Khi đó độ phức tạp thời gian sẽ là O(E log V). Ở đây, E là số cạnh và V là số đỉnh.

Độ phức tạp của không gian là O(V²), vì chúng tôi đang sử dụng ma trận kề (mảng 2D). Độ phức tạp của không gian có thể được tối ưu hóa bằng cách sử dụng danh sách kề hoặc cấu trúc dữ liệu hàng đợi.

Câu Hỏi Thường Gặp

Các tác nhân lập kế hoạch đường đi bằng trí tuệ nhân tạo trong robot, xe tự hành và NPC trong trò chơi sử dụng thuật toán Dijkstra để tìm các tuyến đường có chi phí thấp nhất trên đồ thị có trọng số. Môi trường học tăng cường cũng dựa vào thuật toán này để tính toán các đường dẫn tham chiếu tối ưu cho việc chia sẻ phần thưởng.ping và đánh giá.

Đúng vậy. Các trợ lý lập trình AI như GitHub Copilot và GPT có thể tạo ra thuật toán Dijkstra. Python, C++, hoặc là JavaBao gồm cả các biến thể hàng đợi ưu tiên sử dụng heap. Chúng cũng có thể in ra đường đi ngắn nhất thực tế hoặc điều chỉnh mã cho phù hợp với đồ thị được lưu trữ dưới dạng danh sách kề.

Sử dụng một mảng đơn giản để tìm nút nhỏ nhất, thuật toán Dijkstra chạy trong thời gian O(V²). Với hàng đợi ưu tiên heap nhị phân, nó giảm xuống còn O((V + E) log V), và với heap Fibonacci, nó đạt đến O(E + V log V), tốt nhất cho đồ thị thưa.

Thuật toán Dijkstra chốt một đỉnh ngay khi chọn được khoảng cách ngắn nhất hiện tại. Một cạnh âm sau đó có thể làm cho đường đi dài hơn trở nên rẻ hơn, nhưng đỉnh đã được chốt sẽ không bao giờ được thăm lại, do đó thuật toán báo cáo khoảng cách ngắn nhất không chính xác.

Chọn thuật toán Dijkstra khi mọi trọng số cạnh đều không âm vì nó nhanh hơn với độ phức tạp O((V+E) log V). Chọn thuật toán Bellman-Ford khi các cạnh có thể có trọng số âm hoặc bạn cần phát hiện các chu trình có trọng số âm; thời gian chạy O(V·E) của nó là sự đánh đổi.

Google Maps sử dụng các biến thể và thuật toán kế thừa của Dijkstra, bao gồm A* và Con.tracHệ thống phân cấp, được tinh chỉnh cho mạng lưới đường bộ và giao thông thực tế. Ý tưởng cơ bản về mở rộng tham lam với chi phí tích lũy tối thiểu vẫn là đóng góp cốt lõi của thuật toán Dijkstra.

Thuật toán A* mở rộng thuật toán Dijkstra bằng cách thêm ước lượng heuristic về khoảng cách đến mục tiêu, mở rộng ít nút hơn khi có sẵn một heuristic tốt. Thuật toán Dijkstra khám phá theo mọi hướng, trong khi A* ưu tiên tìm kiếm về phía mục tiêu, do đó nhanh hơn trong thực tế.

Ngoài bản đồ, thuật toán Dijkstra còn được sử dụng trong các giao thức định tuyến OSPF và IS-IS trên internet, tối ưu hóa cấu trúc mạng, định tuyến cuộc gọi điện thoại, lập kế hoạch chuyển động cho robot, truy vấn kết nối ngắn nhất trên mạng xã hội và giảm thiểu chi phí chuyến bay của các hãng hàng không.

Tóm tắt bài viết này với: