Algorytm Dijkstry
![]() 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ótszej ścieżki z pojedynczego źródła w grafie o nieujemnych wagach krawędzi.
Działanie
[edytuj | edytuj kod]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 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[1].
Algorytm Dijkstry jest przykładem algorytmu zachłannego[2].
Algorytm
[edytuj | edytuj kod]Przez oznaczamy wierzchołek źródłowy, to waga krawędzi w grafie.
- Stwórz tablicę odległości od źródła dla wszystkich wierzchołków grafu. Na początku zaś dla wszystkich pozostałych wierzchołków.
- Utwórz kolejkę priorytetową wszystkich wierzchołków grafu. Priorytetem kolejki jest aktualnie wyliczona odległość od wierzchołka źródłowego
- Dopóki kolejka nie jest pusta:
- Usuń z kolejki wierzchołek o najniższym priorytecie (wierzchołek najbliższy źródła, który nie został jeszcze rozważony)
- Dla każdego sąsiada wierzchołka dokonaj relaksacji poprzez jeśli (poprzez da się dojść do szybciej niż dotychczasową ścieżką), to
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
Zastosowanie
[edytuj | edytuj kod]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).
Pseudokod
[edytuj | edytuj kod]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])
Dowód poprawności
[edytuj | edytuj kod]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:
- Dla każdego wierzchołka liczba jest długością najkrótszej ścieżki od do
- Dla każdego wierzchołka jest długością najkrótszej ścieżki do prowadzącej tylko przez wierzchołki z
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ść
[edytuj | edytuj kod]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:
- wykorzystując „naiwną” implementację poprzez zwykłą tablicę, otrzymujemy algorytm o złożoności
- w implementacji kolejki poprzez kopiec, złożoność wynosi
- po zastąpieniu zwykłego kopca kopcem Fibonacciego złożoność zmienia się na
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.
Problemy i algorytmy pokrewne
[edytuj | edytuj kod]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 o bardzo podobny pomysł co algorytm Dijkstry.
Przypisy
[edytuj | edytuj kod]- ↑ Algorytm Dijkstry. edu.i-lo.tarnow.pl. [zarchiwizowane z tego adresu (2009-01-25)]..
- ↑ Algorytm Dijkstry.
Bibliografia
[edytuj | edytuj kod]- E. W. Dijkstra: A note on two problems in connexion with graphs. In Numerische Mathematik, 1 (1959), S. 269–271.
- Cormen, Thomas H.; Leiserson, Charles E.; Rivest, Ronald L.; Stein, Clifford Wprowadzenie do algorytmów, wyd. 7, WNT 2007, ISBN 83-204-3149-2.
Linki zewnętrzne
[edytuj | edytuj kod]- Algorytm Dijkstry na wazniak.mimuw.edu.pl
- Implementacja w języku C++
- Animacja algorytmu Dijkstry. optlab-server.sce.carleton.ca. [zarchiwizowane z tego adresu (2014-12-20)].
- Przykład wykonania algorytmu Dijkstry krok po kroku