Ilustracja działania algorytmu | |
| Rodzaj |
Znajdowanie najkrótszej ścieżki |
|---|---|
| Struktura danych | |
| Złożoność | |
| Czasowa |
|
| Pamięciowa |
- przy użyciu kopca Fibonacciego |
Algorytm Dijkstry, opracowany przez holenderskiego informatyka Edsgera Dijkstrę, służy do znajdowania najkrótszych ścieżek z wybranego wierzchołka do pozostałych wierzchołków w grafie o nieujemnych wagach krawędzi.
Mając dany graf z wyróżnionym wierzchołkiem (źródłem) algorytm znajduje odległości od źródła do wszystkich pozostałych wierzchołków. Łatwo jest zmodyfikować go tak, aby szukał wyłącznie (najkrótszej) ścieżki do jednego ustalonego wierzchołka, po prostu przerywając działanie w momencie dojścia do wierzchołka docelowego, bądź transponując tablicę incydencji grafu.
Algorytm Dijkstry znajduje w grafie wszystkie najkrótsze ścieżki pomiędzy wybranym wierzchołkiem a wszystkimi pozostałymi, przy okazji wyliczając również koszt przejścia każdej z tych ścieżek.
Algorytm Dijkstry jest przykładem algorytmu zachłannego.
Przez oznaczamy wierzchołek źródłowy, to waga krawędzi w grafie.
Na końcu tablica zawiera najkrótsze odległości do wszystkich wierzchołków.
Dodatkowo możemy w tablicy poprzednik przechowywać dla każdego wierzchołka numer jego bezpośredniego poprzednika na najkrótszej ścieżce, co pozwoli na odtworzenie pełnej ścieżki od źródła do każdego wierzchołka – przy każdej relaksacji w ostatnim punkcie staje się poprzednikiem
Z algorytmu Dijkstry można skorzystać przy obliczaniu najkrótszej drogi do danej miejscowości. Wystarczy przyjąć, że każdy z punktów skrzyżowań dróg to jeden z wierzchołków grafu, a odległości między punktami to wagi krawędzi.
Jest często używany w sieciach komputerowych, np. przy trasowaniu (przykładowo w protokole OSPF).
Dijkstra(G,w,s):
dla każdego wierzchołka v w V[G] wykonaj
d[v] := nieskończoność
poprzednik[v] := niezdefiniowane
d[s] := 0
Q := V
dopóki Q niepuste wykonaj
u := Zdejmij_Min(Q)
dla każdego wierzchołka v – sąsiada u wykonaj
jeżeli d[v] > d[u] + w(u, v) to
d[v] := d[u] + w(u, v)
poprzednik[v] := u
Wyświetl("Droga wynosi: " + d[v])
Oznaczmy przez zbiór wierzchołków, które zostały już zdjęte z kolejki. Dowód opiera się na następujących dwóch faktach (niezmiennikach), prawdziwych przez cały czas trwania algorytmu:
Na początku oba fakty są oczywiste ( jest zbiorem pustym). Przy zdejmowaniu wierzchołka z kolejki wiemy, na podstawie faktu 2, że nie da się do niego dojść żadną krótszą drogą przez wierzchołki z Z drugiej strony, ponieważ ma najniższy priorytet, przejście przez jakikolwiek inny wierzchołek spoza dałoby od razu co najmniej tak samo długą ścieżkę. A zatem dołączając wierzchołek do zachowujemy prawdziwość faktu 1. Następnie musimy uwzględnić fakt, że najkrótsza ścieżka do jakiegoś wierzchołka po wierzchołkach z nowego zbioru może teraz zawierać wierzchołek Ale wtedy musi on być ostatnim na niej wierzchołkiem (do każdego innego dałoby się dojść krócej, nie używając ), a zatem jej długość równa jest i zostanie prawidłowo obliczona w następnym kroku algorytmu.
Złożoność obliczeniowa algorytmu Dijkstry zależy od liczby wierzchołków i krawędzi grafu. O rzędzie złożoności decyduje implementacja kolejki priorytetowej:
Pierwszy wariant jest optymalny dla grafów gęstych (czyli jeśli ), drugi jest szybszy dla grafów rzadkich trzeci jest bardzo rzadko używany ze względu na duży stopień skomplikowania i niewielki w porównaniu z nim zysk czasowy.
Algorytm Dijkstry nie działa, jeśli w grafie występują krawędzie z ujemnymi wagami – w tym wypadku używa się wolniejszego, lecz bardziej ogólnego algorytmu Bellmana-Forda. Jeśli graf nie jest ważony (wszystkie wagi mają wielkość 1), zamiast algorytmu Dijkstry wystarczy algorytm przeszukiwania grafu wszerz.
Algorytm A* jest pewnym uogólnieniem algorytmu Dijkstry, które pozwala przeszukiwać tylko część grafu, jednak wymaga dodatkowej wstępnej informacji (heurystyki) o odległościach wierzchołków.
Algorytm Prima znajdowania minimalnego drzewa rozpinającego oparty jest na koncepcji bardzo podobnej do algorytmu Dijkstry.