W tym artykule omówimy jeden z najbardziej znanych algorytmów najkrótszej ścieżki, czyli algorytm najkrótszej ścieżki Dijkstry, który został opracowany przez holenderskiego informatyka Edsgera W. Dijkstrę w 1956 roku. Ponadto przeprowadzimy analizę złożoności tego algorytmu, a także zobacz, czym różni się od innych algorytmów najkrótszej ścieżki.
Spis treści
- Algorytm Dijkstry
- Potrzeba algorytmu Dijkstry (cel i przypadki użycia)
- Czy algorytm Dijkstry może działać zarówno na grafach skierowanych, jak i nieskierowanych?
- Algorytm algorytmu Dijkstry
- Jak działa algorytm Dijkstry?
- Pseudokod algorytmu Dijkstry
- Implementacja algorytmu Dijkstry:
- Algorytmy Dijkstry a algorytm Bellmana-Forda
- Algorytm Dijkstry kontra algorytm Floyda-Warshalla
- Algorytm Dijkstry a algorytm A*
- Ćwicz problemy z algorytmem Dijkstry
- Wniosek:

Algorytm Dijkstry:
Algorytm Dijkstry to popularny algorytm rozwiązywania wielu problemów z najkrótszą ścieżką z jednego źródła, mających nieujemną wagę krawędzi na grafach, tj. polega na znalezieniu najkrótszej odległości między dwoma wierzchołkami grafu. Został wymyślony przez holenderskiego informatyka Edsger W. Dijkstra w 1956 r.
Algorytm przechowuje zbiór odwiedzonych wierzchołków i zbiór nieodwiedzonych wierzchołków. Zaczyna się od wierzchołka źródłowego i iteracyjnie wybiera nieodwiedzony wierzchołek o najmniejszej wstępnej odległości od źródła. Następnie odwiedza sąsiadów tego wierzchołka i aktualizuje ich wstępne odległości, jeśli zostanie znaleziona krótsza ścieżka. Proces ten trwa aż do osiągnięcia wierzchołka docelowego lub odwiedzenia wszystkich osiągalnych wierzchołków.
Potrzeba algorytmu Dijkstry (cel i przypadki użycia)
Zapotrzebowanie na algorytm Dijkstry pojawia się w wielu zastosowaniach, w których kluczowe znaczenie ma znalezienie najkrótszej ścieżki między dwoma punktami.
Na przykład , Może być używany w protokołach routingu w sieciach komputerowych, a także używany przez systemy map do znalezienia najkrótszej ścieżki między punktem początkowym a miejscem docelowym (jak wyjaśniono w Jak działają Mapy Google? )
Czy algorytm Dijkstry może działać zarówno na grafach skierowanych, jak i nieskierowanych?
Tak , algorytm Dijkstry może pracować zarówno na grafach skierowanych, jak i nieskierowanych, ponieważ algorytm ten jest przeznaczony do pracy na dowolnym typie grafów, o ile spełnia wymagania dotyczące posiadania nieujemnych wag krawędzi i spójności.
- Na grafie skierowanym każda krawędź ma kierunek, wskazujący kierunek ruchu pomiędzy wierzchołkami połączonymi krawędzią. W tym przypadku algorytm poszukuje najkrótszej ścieżki podążając za kierunkiem krawędzi.
- Na grafie nieskierowanym krawędzie nie mają kierunku, a algorytm może przemieszczać się wzdłuż krawędzi zarówno do przodu, jak i do tyłu, szukając najkrótszej ścieżki.
Algorytm algorytmu Dijkstry:
- Oznacz węzeł źródłowy bieżącą odległością 0, a resztę nieskończonością.
- Ustaw nieodwiedzony węzeł o najmniejszej bieżącej odległości jako bieżący węzeł.
- Dla każdego sąsiada N bieżącego węzła dodaje bieżącą odległość sąsiedniego węzła z wagą krawędzi łączącej 0->1. Jeśli jest mniejsza niż bieżąca odległość węzła, ustaw ją jako nową aktualną odległość N.
- Oznacz bieżący węzeł 1 jako odwiedzony.
- Przejdź do kroku 2, jeśli są jakieś nieodwiedzone węzły.
Jak działa algorytm Dijkstry?
Zobaczmy, jak działa algorytm Dijkstry na przykładzie podanym poniżej:
Algorytm Dijkstry wygeneruje najkrótszą ścieżkę od węzła 0 do wszystkich pozostałych węzłów na wykresie.
Rozważ poniższy wykres:
Algorytm Dijkstry
Algorytm wygeneruje najkrótszą ścieżkę od węzła 0 do wszystkich pozostałych węzłów na grafie.
W przypadku tego wykresu założymy, że waga krawędzi reprezentuje odległość między dwoma węzłami.
co to jest stos w JavieJak widzimy, mamy najkrótszą ścieżkę z,
Węzeł 0 do węzła 1, od
Węzeł 0 do węzła 2, od
Węzeł 0 do węzła 3, od
Węzeł 0 do węzła 4, od
Węzeł 0 do węzła 6.Początkowo mamy zestaw zasobów podany poniżej:
- Odległość od węzła źródłowego do niego samego wynosi 0. W tym przykładzie węzeł źródłowy wynosi 0.
- Odległość od węzła źródłowego do wszystkich pozostałych węzłów jest nieznana, dlatego wszystkie oznaczamy jako nieskończoność.
Przykład: 0 -> 0, 1-> ∞,2-> ∞,3-> ∞,4-> ∞,5-> ∞,6-> ∞.
- będziemy mieli także tablicę nieodwiedzonych elementów, które będą śledzić nieodwiedzone lub nieoznaczone węzły.
- Algorytm zakończy się, gdy wszystkie węzły zostaną oznaczone jako odwiedzone, a odległość między nimi zostanie dodana do ścieżki. Nieodwiedzone węzły:- 0 1 2 3 4 5 6.
Krok 1: Zacznij od węzła 0 i oznacz węzeł jako odwiedzony, jak możesz sprawdzić na obrazku poniżej odwiedzony węzeł jest zaznaczony na czerwono.
Algorytm Dijkstry
Krok 2: Sprawdź sąsiadujące węzły. Teraz mamy wybór (albo wybierz Węzeł 1 z odległością 2, albo wybierz Węzeł 2 z odległością 6) i wybierz Węzeł z minimalną odległością. W tym kroku Węzeł 1 to Minimalna odległość sąsiadującego węzła, więc oznacz go jako odwiedzony i zsumuj odległość.
Odległość: węzeł 0 -> węzeł 1 = 2
Algorytm Dijkstry
Krok 3: Następnie przejdź dalej i sprawdź sąsiadujący węzeł, którym jest węzeł 3, więc oznacz go jako odwiedzony i dodaj odległość. Teraz odległość będzie wynosić:
Odległość: węzeł 0 -> węzeł 1 -> węzeł 3 = 2 + 5 = 7
Algorytm Dijkstry
Krok 4: Ponownie mamy dwie możliwości dla sąsiednich węzłów (albo możemy wybrać węzeł 4 z odległością 10, albo możemy wybrać węzeł 5 z odległością 15), więc wybierz węzeł z minimalną odległością. W tym kroku Węzeł 4 to Minimalna odległość sąsiadującego węzła, więc oznacz go jako odwiedzony i zsumuj odległość.
Odległość: Węzeł 0 -> Węzeł 1 -> Węzeł 3 -> Węzeł 4 = 2 + 5 + 10 = 17
Algorytm Dijkstry
prymitywne typy danych w JavieKrok 5: Ponownie przejdź do przodu i sprawdź sąsiadujący węzeł, który jest Węzeł 6 , więc oznacz jako odwiedzone i zsumuj odległość. Teraz odległość będzie wynosić:
Odległość: Węzeł 0 -> Węzeł 1 -> Węzeł 3 -> Węzeł 4 -> Węzeł 6 = 2 + 5 + 10 + 2 = 19
Algorytm Dijkstry
Zatem najkrótsza odległość od wierzchołka źródłowego wynosi 19, co jest wartością optymalną
Pseudokod algorytmu Dijkstry
funkcja Dijkstra(Wykres, źródło):
// Zainicjuj odległości do wszystkich węzłów jako nieskończoność, a do węzła źródłowego jako 0.odległości = mapa (wszystkie węzły -> nieskończoność)
odległości = 0
połączenie sql// Zainicjuj pusty zestaw odwiedzonych węzłów i kolejkę priorytetową, aby śledzić węzły do odwiedzenia.
odwiedzony = pusty zestaw
kolejka = nowa Kolejka Priorytetów()
kolejka.enqueue(źródło, 0)// Pętla do momentu odwiedzenia wszystkich węzłów.
póki kolejka nie jest pusta:
// Usuń z kolejki węzeł znajdujący się w najmniejszej odległości od kolejki priorytetowej.
bieżący = kolejka.dequeue()// Jeśli węzeł był już odwiedzony, pomiń go.
jeśli aktualnie odwiedzasz:
Kontynuować// Oznacz węzeł jako odwiedzony.
odwiedził.add(bieżący)// Sprawdź wszystkie sąsiednie węzły, aby zobaczyć, czy ich odległości wymagają aktualizacji.
dla sąsiada w Graph.neighbors(current):
// Oblicz wstępną odległość do sąsiada przez bieżący węzeł.
tentative_distance = odległości [bieżący] + Graph.distance (bieżący, sąsiad)// Jeśli wstępna odległość jest mniejsza niż bieżąca odległość do sąsiada, zaktualizuj odległość.
jeśli wstępna_odległość
odległości[sąsiad] = odległość_wstępna// Kolejkuj sąsiada z jego nową odległością, aby uwzględnić go w przyszłych wizytach.
kolejka.enqueue(sąsiad, odległości[sąsiad])// Zwraca obliczone odległości od źródła do wszystkich pozostałych węzłów na wykresie.
odległości powrotne
Implementacja algorytmu Dijkstry:
Istnieje kilka sposobów implementacji algorytmu Dijkstry, ale najczęstsze z nich to:
- Kolejka priorytetowa (implementacja oparta na stercie):
- Implementacja oparta na tablicach:
1. Algorytm najkrótszej ścieżki Dijkstry wykorzystujący kolejkę priorytetową (sterta)
W tej implementacji otrzymujemy graf i wierzchołek źródłowy na grafie, znajdując najkrótszą ścieżkę od źródła do wszystkich wierzchołków w danym grafie.
Przykład:
Wejście: Źródło = 0
Rohit Shetty, aktorPrzykład
Wyjście: Wierzchołek
Odległość wierzchołka od źródła
0 -> 0
1 -> 2
2 -> 6
3 -> 7
4 -> 17
5 -> 22
6 -> 19
Poniżej znajduje się algorytm oparty na powyższym pomyśle:
- Zainicjuj wartości odległości i kolejkę priorytetową.
- Wstaw węzeł źródłowy do kolejki priorytetowej z odległością 0.
- Chociaż kolejka priorytetowa nie jest pusta:
- Wyodrębnij węzeł z minimalną odległością od kolejki priorytetowej.
- Zaktualizuj odległości sąsiadów, jeśli zostanie znaleziona krótsza ścieżka.
- Wstaw zaktualizowanych sąsiadów do kolejki priorytetowej.
Poniżej znajduje się implementacja C++ powyższego podejścia:
C++ // Program to find Dijkstra's shortest path using // priority_queue in STL #include using namespace std; #define INF 0x3f3f3f3f // iPair ==>Para całkowita typedef para iPara; // Ta klasa reprezentuje graf skierowany za pomocą // klasy reprezentacji listy sąsiedztwa Graph { int V; // Liczba wierzchołków // W grafie ważonym musimy przechowywać wierzchołki // i parę wag dla każdej listy krawędzi>* przym.; public: Graph(int V); // Konstruktor // funkcja dodająca krawędź do wykresu void addEdge(int u, int v, int w); // drukuje najkrótszą ścieżkę z s void shortestPath(int s); }; // Przydziela pamięć dla listy sąsiedztwa Graph::Graph(int V) { this->V = V; adj = nowa lista [V]; } void Graph::addEdge(int u, int v, int w) { adj[u].push_back(make_pair(v, w)); adj[v].push_back(make_pair(u, w)); } // Drukuje najkrótsze ścieżki od src do wszystkich pozostałych wierzchołków void Graph::shortestPath(int src) { // Utwórz kolejkę priorytetową do przechowywania wierzchołków, które // są wstępnie przetwarzane. To dziwna składnia w C++. // Link poniżej zawiera szczegółowe informacje na temat tej składni // https://www.techcodeview.com priorytet_queue , większy > pq; // Utwórz wektor odległości i zainicjuj // wszystkie odległości jako wektory nieskończone (INF). odst(V, INF); // Wstaw źródło do kolejki priorytetowej i zainicjuj // jego odległość jako 0. pq.push(make_pair(0, src)); odległość[źródło] = 0; /* Zapętlanie do momentu, aż kolejka priorytetowa stanie się pusta (lub nie zostaną sfinalizowane wszystkie odległości) */ while (!pq.empty()) { // Pierwszy wierzchołek pary to minimalna odległość // wierzchołek, wyodrębnij go z kolejki priorytetowej. // etykieta wierzchołka jest przechowywana w drugiej parze ( // należy to zrobić w ten sposób, // aby zachować // posortowaną odległość wierzchołków (odległość musi być pierwszym elementem // w parze) int u = pq.top().sekunda; pq.pop(); // 'i' służy do pobrania wszystkich sąsiadujących wierzchołków // listy wierzchołków>::iterator i; for (i = adj[u].begin(); i != adj[u].end(); ++i) { // Uzyskaj etykietę wierzchołka i wagę bieżącego // sąsiadującego z u. int v = (*i).pierwszy; int waga = (*i).sekunda; // Jeśli ścieżka od v do u jest krótka. if (dist[v]> dist[u] + waga) { // Aktualizowanie odległości v dist[v] = dist[u] + waga; pq.push(make_pair(odległość[v], v)); } } } // Wydrukuj najkrótsze odległości zapisane w dist[] printf('Odległość wierzchołka od źródła
'); for (int i = 0; tj< V; ++i) printf('%d %d
', i, dist[i]); } // Driver program to test methods of graph class int main() { // create the graph given in above figure int V = 7; Graph g(V); // making above shown graph g.addEdge(0, 1, 2); g.addEdge(0, 2, 6); g.addEdge(1, 3, 5); g.addEdge(2, 3, 8); g.addEdge(3, 4, 10); g.addEdge(3, 5, 15); g.addEdge(4, 6, 2); g.addEdge(5, 6, 6); g.shortestPath(0); return 0; }>
Jawa import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.PriorityQueue; public class DijkstraAlgoForShortestDistance { static class Node implements Comparable{ w telewizji; int odległość; public Node(int v, int odległość) { this.v = v; this.distance = odległość; } @Override public int CompareTo(węzeł n) { if (this.distance<= n.distance) { return -1; } else { return 1; } } } static int[] dijkstra( int V, ArrayList >> adj, int S) { boolean[] odwiedzone = nowe boolean[V]; HashMapa mapa = nowa HashMap(); Kolejka priorytetowaq = nowa Kolejka Priorytetów(); map.put(S, nowy węzeł(S, 0)); q.add(nowy węzeł(S, 0)); while (!q.isEmpty()) { Węzeł n = q.poll(); int v = n.v; int odległość = n.odległość; odwiedziliśmy[v] = prawda; Lista tablic > adjList = adj.get(v); dla (ArrayList adjLink : adjList) { if (visited[adjLink.get(0)] == false) { if (!map.containsKey(adjLink.get(0))) { map.put( adjLink.get(0), nowy węzeł (v, odległość + adjLink.get(1))); } else { Węzeł sn = map.get(adjLink.get(0)); if (odległość + adjLink.get(1)< sn.distance) { sn.v = v; sn.distance = distance + adjLink.get(1); } } q.add(new Node(adjLink.get(0), distance + adjLink.get(1))); } } } int[] result = new int[V]; for (int i = 0; i < V; i++) { result[i] = map.get(i).distance; } return result; } public static void main(String[] args) { ArrayList >> adj = nowa ArrayList(); HashMapa >> mapa = nowa HashMap(); int V = 6; int E = 5; int[] u = { 0, 0, 1, 2, 4 }; int[] v = { 3, 5, 4, 5, 5 }; int[] w = { 9, 4, 4, 10, 3 }; for (int i = 0; tj< E; i++) { ArrayList krawędź = nowa ArrayList(); krawędź.add(v[i]); krawędź.add(w[i]); Lista tablic > adjLista; if (!map.containsKey(u[i])) { adjList = nowa ArrayList(); } else { adjList = map.get(u[i]); } adjList.add(krawędź); map.put(u[i], adjList); Lista tablic krawędź2 = nowa ArrayList(); Edge2.add(u[i]); Edge2.add(w[i]); Lista tablic > adjLista2; if (!map.containsKey(v[i])) { adjList2 = nowa ArrayList(); } else { adjList2 = map.get(v[i]); } adjList2.add(krawędź2); map.put(v[i], adjList2); } for (int i = 0; tj< V; i++) { if (map.containsKey(i)) { adj.add(map.get(i)); } else { adj.add(null); } } int S = 1; // Input sample //[0 [[3, 9], [5, 4]], // 1 [[4, 4]], // 2 [[5, 10]], // 3 [[0, 9]], // 4 [[1, 4], [5, 3]], // 5 [[0, 4], [2, 10], [4, 3]] //] int[] result = DijkstraAlgoForShortestDistance.dijkstra( V, adj, S); System.out.println(Arrays.toString(result)); } }> Pyton # Python implementation of Dijkstra Algorithm import heapq class Node: def __init__(self, v, distance): self.v = v self.distance = distance def __lt__(self, other): return self.distance < other.distance def dijkstra(V, adj, S): visited = [False] * V map = {} q = [] map[S] = Node(S, 0) heapq.heappush(q, Node(S, 0)) while q: n = heapq.heappop(q) v = n.v distance = n.distance visited[v] = True adjList = adj[v] for adjLink in adjList: if not visited[adjLink[0]]: if adjLink[0] not in map: map[adjLink[0]] = Node(v, distance + adjLink[1]) else: sn = map[adjLink[0]] if distance + adjLink[1] < sn.distance: sn.v = v sn.distance = distance + adjLink[1] heapq.heappush(q, Node(adjLink[0], distance + adjLink[1])) result = [0] * V for i in range(V): result[i] = map[i].distance return result def main(): adj = [[] for _ in range(6)] V = 6 E = 5 u = [0, 0, 1, 2, 4] v = [3, 5, 4, 5, 5] w = [9, 4, 4, 10, 3] for i in range(E): edge = [v[i], w[i]] adj[u[i]].append(edge) edge2 = [u[i], w[i]] adj[v[i]].append(edge2) S = 1 result = dijkstra(V, adj, S) print(result) if __name__ == '__main__': main() # This code is contributed by ragul21> C# // C# Code: using System; using System.Collections.Generic; public class Graph { // No. of vertices private int V; // adjacency list private List>[] przym.; // Konstruktor public Graph(int v) { V = v; adj = nowa lista>[v]; for (int i = 0; tj< v; ++i) adj[i] = new List>(); } // funkcja dodająca krawędź do wykresu public void addEdge(int u, int v, int w) { adj[u].Add(Tuple.Create(v, w)); adj[v].Add(Tuple.Create(u, w)); } // drukuje najkrótszą ścieżkę z publicznego void shortestPath(int s) { // Utwórz kolejkę priorytetową do przechowywania wierzchołków, które // są wstępnie przetwarzane. var pq = nowa kolejka priorytetów>(); // Utwórz wektor odległości i zainicjalizuj // wszystkie odległości jako nieskończone (INF) var dist = new int[V]; for (int i = 0; tj< V; i++) dist[i] = int.MaxValue; // Insert source itself in priority queue and // initialize its distance as 0. pq.Enqueue(Tuple.Create(0, s)); dist[s] = 0; /* Looping till priority queue becomes empty (or all distances are not finalized) */ while (pq.Count != 0) { // The first vertex in pair is the minimum // distance vertex, extract it from priority // queue. vertex label is stored in second of // pair (it has to be done this way to keep the // vertices sorted distance (distance must be // first item in pair) var u = pq.Dequeue().Item2; // 'i' is used to get all adjacent vertices of a // vertex foreach(var i in adj[u]) { // Get vertex label and weight of current // adjacent of u. int v = i.Item1; int weight = i.Item2; // If there is shorted path to v through u. if (dist[v]>dist[u] + waga) { // Aktualizacja odległości v dist[v] = dist[u] + waga; pq.Enqueue(Tuple.Create(odległość[v], v)); } } } // Wydrukuj najkrótsze odległości zapisane w dist[] Console.WriteLine('Odległość wierzchołka od źródła'); for (int i = 0; tj< V; ++i) Console.WriteLine('{0} {1}', i, dist[i]); } } public class PriorityQueue{prywatna lista tylko do odczytu_dane; Porównanie prywatne tylko do odczytu_porównane; public PriorityQueue(): this(Porównaj.Default) { } public PriorityQueue(IComparerporównaj): this(compare.Compare) { } public PriorityQueue(Comparisonporównanie) { _data = nowa lista(); _porównaj = porównanie; } public void Kolejka(T pozycja) { _data.Add(item); var childIndex = _data.Count - 1; while (childIndex> 0) { var parentIndex = (childIndex - 1) / 2; if (_compare(_data[childIndex], _data[parentIndex])>= 0) przerwa; T tmp = _data[indekspodrzędny]; _data[childIndex] = _data[parentIndex]; _data[indeks_nadrzędny] = tmp; Indeks Dziecka = Indeks Rodzica; } } public T Dequeue() { // zakłada, że pq nie jest puste; do wywołania kodu var lastElement = _data.Count - 1; var frontItem = _data[0]; _data[0] = _data[ostatniElement]; _data.RemoveAt(lastElement); --ostatniElement; varindeks rodzica = 0; while (true) { var childIndex = parentIndex * 2 + 1; if (childIndex> lastElement) przerwa; // Koniec drzewa varrightChild = childIndex + 1; jeśli (prawoDziecko<= lastElement && _compare(_data[rightChild], _data[childIndex]) < 0) childIndex = rightChild; if (_compare(_data[parentIndex], _data[childIndex]) <= 0) break; // Correct position T tmp = _data[parentIndex]; _data[parentIndex] = _data[childIndex]; _data[childIndex] = tmp; parentIndex = childIndex; } return frontItem; } public T Peek() { T frontItem = _data[0]; return frontItem; } public int Count { get { return _data.Count; } } } class Program { // Driver program to test methods of graph class static void Main(string[] args) { // create the graph given in above figure int V = 7; Graph g = new Graph(V); // making above shown graph g.addEdge(0, 1, 2); g.addEdge(0, 2, 6); g.addEdge(1, 3, 5); g.addEdge(2, 3, 8); g.addEdge(3, 4, 10); g.addEdge(3, 5, 15); g.addEdge(4, 6, 2); g.addEdge(5, 6, 6); g.shortestPath(0); } }> JavaScript class PriorityQueue { constructor() { this.queue = []; } enqueue(element, priority) { this.queue.push({ element, priority }); this.queue.sort((a, b) =>a.priorytet - b.priorytet); } dequeue() { if (this.isEmpty()) { return null; } zwróć this.queue.shift().element; } isEmpty() { zwróć tę.długość.kolejki === 0; } } klasa Wykres { konstruktor(V) { this.V = V; this.adj = nowa tablica(V); dla (niech i = 0; tj< V; i++) { this.adj[i] = []; } } addEdge(u, v, w) { this.adj[u].push({ v, w }); this.adj[v].push({ v: u, w }); } shortestPath(src) { const pq = new PriorityQueue(); const dist = new Array(this.V).fill(Infinity); const visited = new Array(this.V).fill(false); pq.enqueue(src, 0); dist[src] = 0; while (!pq.isEmpty()) { const u = pq.dequeue(); if (visited[u]) continue; visited[u] = true; for (const { v, w } of this.adj[u]) { if (!visited[v] && dist[u] + w < dist[v]) { dist[v] = dist[u] + w; pq.enqueue(v, dist[v]); } } } console.log('Vertex Distance from Source'); for (let i = 0; i < this.V; i++) { console.log(`${i} ${dist[i] === Infinity ? 'Infinity' : dist[i]}`); } } } function main() { const V = 7; const g = new Graph(V); g.addEdge(0, 1, 2); g.addEdge(0, 2, 6); g.addEdge(1, 3, 5); g.addEdge(2, 3, 8); g.addEdge(3, 4, 10); g.addEdge(3, 5, 15); g.addEdge(4, 6, 2); g.addEdge(5, 6, 6); g.shortestPath(0); } main();> Ostatnia odpowiedź:

Wyjście
Analiza złożoności algorytmu Dijkstry :
- Złożoność czasowa: O((V + E) log V) , gdzie V to liczba wierzchołków, a E to liczba krawędzi.
- Przestrzeń pomocnicza: O(V), gdzie V to liczba wierzchołków, a E to liczba krawędzi grafu.
2.Implementacja algorytmu Dijkstry w oparciu o tablice (podejście naiwne):
Algorytm Dijkstry można również zaimplementować przy użyciu tablic bez użycia kolejki priorytetowej. Ta implementacja jest prosta, ale może być mniej wydajna, szczególnie w przypadku dużych wykresów.
Algorytm przebiega w następujący sposób:
- Zainicjuj tablicę do przechowywania odległości od źródła do każdego węzła.
- Oznacz wszystkie węzły jako nieodwiedzone.
- Ustaw odległość do węzła źródłowego na 0 i nieskończoność dla wszystkich pozostałych węzłów.
- Powtarzaj, aż wszystkie węzły zostaną odwiedzone:
- Znajdź nieodwiedzony węzeł z najmniejszą znaną odległością.
- Dla bieżącego węzła zaktualizuj odległości do jego nieodwiedzonych sąsiadów.
- Oznacz bieżący węzeł jako odwiedzony.
Analiza złożoności:
- Złożoność czasowa: W najgorszym przypadku O(V^2), gdzie V jest liczbą wierzchołków. Można to poprawić do O(V^2) za pomocą pewnych optymalizacji.
- Przestrzeń pomocnicza: O(V), gdzie V to liczba wierzchołków, a E to liczba krawędzi grafu.
Algorytmy Dijkstry a algorytm Bellmana-Forda
Algorytm Dijkstry i Algorytm Bellmana-Forda oba służą do znajdowania najkrótszej ścieżki na wykresie ważonym, ale mają pewne kluczowe różnice. Oto główne różnice między algorytmem Dijkstry a algorytmem Bellmana-Forda:
| Funkcja: | Dijkstry | Bellmana Forda |
|---|---|---|
| Optymalizacja | zoptymalizowany pod kątem znajdowania najkrótszej ścieżki między pojedynczym węzłem źródłowym a wszystkimi innymi węzłami na wykresie z nieujemnymi wagami krawędzi | Algorytm Bellmana-Forda jest zoptymalizowany pod kątem znajdowania najkrótszej ścieżki pomiędzy pojedynczym węzłem źródłowym a wszystkimi pozostałymi węzłami na wykresie z ujemnymi wagami krawędzi. |
| Relaks | Algorytm Dijkstry wykorzystuje podejście zachłanne, w którym wybiera węzeł o najmniejszej odległości i aktualizuje swoich sąsiadów | algorytm Bellmana-Forda rozluźnia wszystkie krawędzie w każdej iteracji, aktualizując odległość każdego węzła, biorąc pod uwagę wszystkie możliwe ścieżki do tego węzła |
| Złożoność czasu | Algorytm Dijkstry ma złożoność czasową O(V^2) dla grafu gęstego i O(E log V) dla grafu rzadkiego, gdzie V to liczba wierzchołków, a E to liczba krawędzi w grafie. | Algorytm Bellmana-Forda ma złożoność czasową O(VE), gdzie V jest liczbą wierzchołków, a E jest liczbą krawędzi grafu. |
| Wagi ujemne | Algorytm Dijkstry nie działa z grafami, które mają ujemne wagi krawędzi, ponieważ zakłada, że wszystkie wagi krawędzi są nieujemne. | Algorytm Bellmana-Forda radzi sobie z ujemnymi wagami krawędzi i może wykrywać cykle z ujemną wagą na grafie. |
Algorytm Dijkstry kontra algorytm Floyda-Warshalla
Algorytm Dijkstry i Algorytm Floyda-Warshalla oba służą do znajdowania najkrótszej ścieżki na wykresie ważonym, ale mają pewne kluczowe różnice. Oto główne różnice między algorytmem Dijkstry a algorytmem Floyda-Warshalla:
| Funkcja: | Dijkstry | Algorytm Floyda-Warshalla |
|---|---|---|
| Optymalizacja | Zoptymalizowany pod kątem znajdowania najkrótszej ścieżki między pojedynczym węzłem źródłowym a wszystkimi innymi węzłami na wykresie z nieujemnymi wagami krawędzi | Algorytm Floyda-Warshalla jest zoptymalizowany pod kątem znajdowania najkrótszej ścieżki pomiędzy wszystkimi parami węzłów na grafie. |
| Technika | Algorytm Dijkstry to algorytm najkrótszej ścieżki z jednego źródła, który wykorzystuje podejście zachłanne i oblicza najkrótszą ścieżkę od węzła źródłowego do wszystkich pozostałych węzłów na wykresie. | Z drugiej strony algorytm Floyda-Warshalla jest algorytmem najkrótszej ścieżki dla wszystkich par, który wykorzystuje programowanie dynamiczne do obliczenia najkrótszej ścieżki między wszystkimi parami węzłów na wykresie. |
| Złożoność czasu | Algorytm Dijkstry ma złożoność czasową O(V^2) dla grafu gęstego i O(E log V) dla grafu rzadkiego, gdzie V to liczba wierzchołków, a E to liczba krawędzi w grafie. | Z drugiej strony algorytm Floyda-Warshalla jest algorytmem najkrótszej ścieżki dla wszystkich par, który wykorzystuje programowanie dynamiczne do obliczenia najkrótszej ścieżki między wszystkimi parami węzłów na wykresie. |
| Wagi ujemne | Algorytm Dijkstry nie działa z grafami, które mają ujemne wagi krawędzi, ponieważ zakłada, że wszystkie wagi krawędzi są nieujemne. | Z drugiej strony algorytm Floyda-Warshalla jest algorytmem najkrótszej ścieżki dla wszystkich par, który wykorzystuje programowanie dynamiczne do obliczenia najkrótszej ścieżki między wszystkimi parami węzłów na wykresie. |
Algorytm Dijkstry a algorytm A*
Algorytm Dijkstry i Algorytm A* oba służą do znajdowania najkrótszej ścieżki na wykresie ważonym, ale mają pewne kluczowe różnice. Oto główne różnice między algorytmem Dijkstry a algorytmem A*:
| Funkcja: | Algorytm A* | |
|---|---|---|
| Technika wyszukiwania | Zoptymalizowany pod kątem znajdowania najkrótszej ścieżki między pojedynczym węzłem źródłowym a wszystkimi innymi węzłami na wykresie z nieujemnymi wagami krawędzi | Algorytm A* to świadomy algorytm wyszukiwania, który wykorzystuje funkcję heurystyczną do kierowania wyszukiwaniem w kierunku węzła docelowego. |
| Funkcja heurystyczna | Algorytm Dijkstry nie wykorzystuje żadnej funkcji heurystycznej i uwzględnia wszystkie węzły grafu. | Algorytm A* wykorzystuje funkcję heurystyczną, która szacuje odległość od bieżącego węzła do węzła docelowego. Ta funkcja heurystyczna jest dopuszczalna, co oznacza, że nigdy nie zawyża rzeczywistej odległości do węzła docelowego |
| Złożoność czasu | Algorytm Dijkstry ma złożoność czasową O(V^2) dla grafu gęstego i O(E log V) dla grafu rzadkiego, gdzie V to liczba wierzchołków, a E to liczba krawędzi w grafie. | Złożoność czasowa algorytmu A* zależy od jakości funkcji heurystycznej. |
| Aplikacja | Algorytm Dijkstry jest używany w wielu zastosowaniach, takich jak algorytmy wyznaczania tras, systemy nawigacji GPS i analiza sieci | . Algorytm A* jest powszechnie stosowany w problemach związanych ze znajdowaniem ścieżki i przechodzeniem po grafach, takich jak gry wideo, robotyka i algorytmy planowania. |
Zadania praktyczne dotyczące algorytmu Dijkstry:
- Algorytm najkrótszej ścieżki Dijkstry | Chciwy Algo-7
- Algorytm Dijkstry do reprezentacji listy sąsiedztwa | Chciwy Algo-8
- Algorytm Dijkstry – implementacja kolejek priorytetowych i tablic
- Algorytm najkrótszej ścieżki Dijkstry wykorzystujący zestaw w STL
- Algorytm najkrótszej ścieżki Dijkstry wykorzystujący STL w C++
- Algorytm najkrótszej ścieżki Dijkstry wykorzystujący kolejkę priorytetów STL
- Algorytm najkrótszej ścieżki Dijkstry wykorzystujący macierz w C++
- Algorytm Dijkstry dla najkrótszej ścieżki z jednego źródła w DAG
- Algorytm Dijkstry wykorzystujący stertę Fibonacciego
- Algorytm najkrótszej ścieżki Dijkstry dla grafów skierowanych z ujemnymi wagami
- Drukowanie ścieżek w algorytmie najkrótszej ścieżki Dijkstry
- Algorytm najkrótszej ścieżki Dijkstry z kolejką priorytetową w Javie




