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.

Algorytm Dijkstry
Ilustracja
Ilustracja działania algorytmu
Rodzaj

Znajdowanie najkrótszej ścieżki

Struktura danych

graf

Złożoność
Czasowa

Pamięciowa

- przy użyciu kopca Fibonacciego

Działanie edytuj

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

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

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

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

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:

  1. Dla każdego wierzchołka   liczba   jest długością najkrótszej ścieżki od   do  
  2. 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

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

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

  1. Algorytm Dijkstry. edu.i-lo.tarnow.pl. [zarchiwizowane z tego adresu (2009-01-25)]..
  2. Algorytm Dijkstry.

Bibliografia edytuj

Linki zewnętrzne edytuj