Dijkstras algoritm i Python & C++ (Exempel)
โก Smart sammanfattning
Dijkstras algoritm berรคknar den kortaste vรคgen frรฅn ett enda kรคllnod till varje annat nod i en viktad graf med icke-negativa kanter. Denna giriga metod ligger till grund fรถr Google Kartrouting, OSPF IP-routing och otaliga anvรคndningsfall fรถr nรคtverkets kortaste vรคg.

Vad รคr den kortaste vรคgen eller kortaste avstรฅndet?
En vรคg frรฅn kรคllnoden till destinationsnoden som kostar ett minimum รคr den kortaste vรคgen eller det kortaste avstรฅndet. Inom grafteori รคr det mรถjligt att ha flera rutter frรฅn en kรคlla till en destination. Bland dessa rutter, om det finns en rutt som kostar ett minimum, kallar vi den den kortaste vรคgen.
Hรคr betyder "kostnad" antalet noder i rutten eller summan av kostnaderna pรฅ varje kant. En vรคg kan ha en eller flera kanter. Fรถrbindelsen mellan tvรฅ noder kallas en "kant". Det finns olika typer av algoritmer fรถr kortaste vรคgen, sรฅsom Dijkstras algoritm och Bellman-Ford-algoritmen.
Hรคr diskuterar vi Dijkstras algoritm. Lรฅt oss titta pรฅ fรถljande viktade graf:
En oriktad-viktad graf
- Termen "viktad" betyder kostnaden fรถr att flytta frรฅn en nod till en annan. Till exempel, om man flyttar frรฅn nod 1 till nod 2, รคr kostnaden eller vikten 1.
- Vรคgen mellan nod 1 och nod 2 kallas kanten.
- โOriktadโ betyder att du kan fรถrflytta dig frรฅn en nod till en annan och tillbaka till fรถregรฅende nod. Sรฅ om vi fรถrsรถker hitta alla rutter frรฅn nod 1 till nod 7, kommer de att vara:
| Rutt eller stig | Pris |
|---|---|
| 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 |
Bland dessa fyra rutter kan vi se att den fรถrsta rutten kostar 7. Sรฅ det รคr den kortaste vรคgen kostnadsmรคssigt.
Kortaste vรคgen
Hur Dijkstras algoritm fungerar
Dijkstras algoritm kan hitta det kortaste avstรฅndet i bรฅde riktade och oriktade viktade grafer. Denna algoritm รคr girig eftersom den alltid vรคljer den kortaste eller nรคrmaste noden frรฅn origo. Termen "girig" betyder att bland en uppsรคttning utfall eller resultat kommer algoritmen att vรคlja det bรคsta av dem.
Hรคr fรถrsรถker vi hitta de kortaste vรคgarna bland alla andra rutter. Sรฅ Dijkstras algoritm hittar alla kortaste vรคgar frรฅn en enda kรคllnod. Som ett resultat beter sig den som en girig algoritm.
I avsnittet "exempel" nedan ser du steg-fรถr-steg-metoden. Det fungerar sรฅ hรคr:
Steg 1) Initiera startnoden med kostnad 0 och resten av noderna med oรคndlig kostnad.
Steg 2) Underhรฅll en array eller lista fรถr att behรฅlla track av de besรถkta noderna.
Steg 3) Uppdatera nodkostnaden med minimikostnaden. Det kan gรถras genom att jรคmfรถra den aktuella kostnaden med vรคgkostnaden (visas i exempelavsnittet).
Steg 4) Fortsรคtt steg 3 tills alla noder har besรถkts.
Efter att ha genomfรถrt alla dessa steg kommer vi att hitta vรคgen som kostar minst frรฅn kรคlla till destination.
Skillnaden mellan Dijkstra och BFS, DFS
Den stรถrsta skillnaden mellan Dijkstra och BFS-DFS รคr att Dijkstra รคr en algoritm fรถr att hitta den kortaste vรคgen, medan BFS och DFS รคr generella algoritmer fรถr att hitta vรคgen. I allmรคnhet tar BFS och DFS inte hรคnsyn till kantkostnader nรคr de hittar vรคgen. Sรฅ dessa algoritmer kan inte garantera den kortaste vรคgen.
2D-rutnรคtsdemonstration av hur BFS fungerar
Algosketch, som visar BFS-demonstration
Denna demonstration indikerar att BFS bara hittar vรคgen. Den bryr sig dock inte om stigens vikt. BFS (Utรถka fรถrsta sรถkningen) antar att resa frรฅn en nod till en annan nod endast kommer att kosta 1.
Lรฅt oss se ett exempeldiagram:
Hรคr hittar BFS en bana pรฅ nivรฅ 2. BFS passerar grafen i nivรฅordning. Sรฅ den rรถr sig sรฅ hรคr:
Steg 1) Bรถrja frรฅn nod "1" och besรถk alla intilliggande noder 2, 3, 4.
Steg 2) Markera noderna 2, 3, 4 som nivรฅ 1 och besรถk deras angrรคnsande noder. Den fortsรคtter att utforska alla angrรคnsande noder tills den nรฅr destinationsnoden.
Nรคr det gรคller DFS kommer den att korsa vรคgen frรฅn 1 till 7 som fรถljande:
- 1โ2โ3โ7 (originalkostnad 10, DFS-kostnad 3)
- 1โ2โ6โ7 (originalkostnad 7, DFS-kostnad 3)
- 1โ3โ7 (originalkostnad 8, DFS-kostnad 2)
- 1โ4โ5โ7 (originalkostnad 13, DFS-kostnad 3)
Som vi ser berรคknar DFS sin vรคgkostnad med antalet kanter. DFS gรถr fรถljande:
- DFS kan hitta en vรคg frรฅn kรคlla (startpunkt) till destination.
- Det kan inte garantera om sรถkvรคgen som upptรคckts frรฅn kรคllnod till destination รคr den kortaste vรคgen eller inte.
Men enligt Dijkstras algoritm vรคljer den kanter baserat pรฅ deras kostnad. Som en girig algoritm kommer den att vรคlja de lรคgsta kostnadsvรคgarna.
Exempel pรฅ Dijkstras algoritm
Dijkstras algoritm anvรคnder kostnaden eller vikten fรถr att berรคkna den totala kostnaden fรถr vรคgen.
Mรฅlet med Dijkstras algoritm รคr att minimera denna totala kostnad eller vikt. I exemplet som visas ovan hittar vi de bรคsta vรคgarna frรฅn nod 1 till nod 7, och berรคknar sedan alla kostnader.
I Dijkstras algoritm hittar den de kortaste vรคgarna genom att berรคkna vikter. Den sรถker inte efter alla mรถjliga vรคgar. Lรฅt oss demonstrera Dijkstras algoritm med ett exempel. Till exempel har du blivit ombedd att hitta den kortaste vรคgen frรฅn nod 1 till 7.
Fรถr denna process ges stegen nedan:
Steg 1) Initiera startkostnaden fรถr noden till 0. Tilldela "Inf" till resten av noderna. Det betyder att det inte finns nรฅgon sรถkvรคg mellan kรคllan och noden, eller att sรถkvรคgen รคnnu inte har besรถkts.
Steg 2) Nรคr du vรคljer nod 1 markeras den som besรถkt. Uppdatera sedan alla angrรคnsande grannar till nod 1. 2, 3, 4 รคr grannoderna till nod 1.
Nรคr vi uppdaterar en kostnad mรฅste vi fรถlja proceduren nedan:
Vi kan uppdatera varje nods kostnad med hjรคlp av formeln ovan. Till exempel var vi vid nod 1 och behรถvde uppdatera kostnaden fรถr dess angrรคnsande noder 2, 3, 4. Efter uppdateringen kommer kostnaderna att se ut sรฅ hรคr:
Steg 3) Fรถr nod "2" รคr grannarna 6 och 3. Vi uppdaterar kostnaden vid "6" genom att jรคmfรถra oรคndligheten (nuvarande vรคrde) med kostnaden fรถr nod 2 + vรคgkostnaden frรฅn 2 till 6. Enkelt uttryckt kommer nod "6" att ha kostnaden 1+3 eller 4.
Nod 3 รคr granne till nod 2. Vi berรคknade dock dess kostnad i fรถregรฅende steg, som var 7. Nu, om vรฅr vรคg รคr 1-2-3, kommer nod 3 att ha en kostnad pรฅ 10. Vรคg 1-2- 3 kommer att kosta 10, medan 1 till 3 kommer att kosta 7.
Steg 4) Fรถr nod 3 รคr den angrรคnsande noden 7. Sรฅ, om vi jรคmfรถr det aktuella vรคrdet fรถr nod 7 med vรคgkostnaden (7+1) eller 8, kommer vi att uppdatera kostnaden fรถr nod 7. Det รคr 8. Sรฅ vi hittar en vรคg frรฅn nod 1 till nod 7, och den รคr 1โ3โ7. Kostnaden รคr 8.
Steg 5) Fรถr nod 4 kommer vi att uppdatera kostnaden fรถr dess angrรคnsande nod i enlighet dรคrmed. Sรฅ nod "5" kommer att ha en uppdaterad kostnad pรฅ 8. Efter steg 4 och 5 kommer det att se ut sรฅ hรคr:
Nu har vรคgen 1-3-7 kostnaden 8 (tidigare). Noden "7" markerades inte som besรถkt eftersom vi kan nรฅ noden "7" frรฅn noden "6". Vรคgen "1-2-6" hade en kostnad pรฅ 4. Sรฅ vรคgen 1-2-6-7 kommer att ha en kostnad pรฅ 7.
Eftersom 7 < 8, kommer den kortaste vรคgen frรฅn kรคllnoden "1" till destinationsnoden "7" att vara 1-2-6-7, och kostnaden รคr 7. Tidigare var den 1-3-7, och kostnaden var 8. Sรฅ den slutliga grafen kommer att se ut sรฅ hรคr:
Kanten markerad med en svart linje รคr vรฅr kortaste vรคg frรฅn 1 till 7, och det kommer att kosta oss 7.
Pseudo Code Dijkstras algoritm
Hรคr รคr pseudokoden fรถr Dijkstras algoritm:
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++ Implementering av Dijkstras algoritm
Att implementera Dijkstras algoritm med hjรคlp av C++, hรคr รคr koden:
#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); }
Produktion:
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 Implementering av Dijkstras algoritm
Att implementera Dijkstras algoritm med hjรคlp av Python, hรคr รคr koden:
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)
Produktion:
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
Vi kan se att algoritmen berรคknar det kortaste avstรฅndet frรฅn kรคllnoden.
Tillรคmpning av Dijkstra Algorithm
Dijkstras algoritm har en mรคngd olika anvรคndningsomrรฅden. Bland dessa anvรคnds den flitigt inom nรคtverksteknik. Hรคr รคr nรฅgra verkliga anvรคndningsomrรฅden fรถr Dijkstras algoritm:
Dijkstra i Google Kartor: Denna algoritm รคr ryggraden fรถr att hitta de kortaste vรคgarna, som vi kan se av kodavsnittet ovan.
Google anvรคnder inte den enkla Dijkstra-algoritmen. Istรคllet anvรคnder den en modifierad version. Nรคr du vรคljer en destination visas flera sรถkvรคgar i Google Kartor. Bland dessa vรคgar sorteras nรฅgra ut fรถr anvรคndaren. Dessa vรคgar vรคljs ut baserat pรฅ "tid". Sรฅ "tid" รคr en kantkostnad fรถr den kortaste vรคgen.
Dijkstra i IP-routing: IP routing รคr en nรคtverksterminologi. Den beskriver hur ditt datapaket skickas till mottagaren via olika vรคgar. Dessa vรคgar bestรฅr av routrar, servrar och annan utrustning. Inom IP-routing finns det olika typer av protokoll.
Dessa protokoll hjรคlper routern att hitta de kortaste vรคgarna fรถr att skicka data. Ett av protokollnamnen รคr "OSPF (Open Shortest Path First)". OSPF anvรคnder Dijkstras algoritm. Routern upprรคtthรฅller en tabell รถver rutter. Varje router delar sin tabell med grannroutrar. Efter att ha mottagit den uppdaterade tabellen mรฅste de berรคkna alla vรคgar igen. Vid den tidpunkten anvรคnder routern Dijkstras algoritm.
Begrรคnsning av Dijkstras algoritm
Dijkstras algoritm kan inte garantera den kortaste vรคgen i en graf med negativa kanter. Dijkstras algoritm fรถljer dessa principer:
- En kortaste vรคg kommer att tas frรฅn en nod till en annan.
- Nรคr den kortaste vรคgen mellan tvรฅ noder har valts kommer den inte att berรคknas igen.
Lรคgg mรคrke till tvรฅ exempel med negativa kanter.
I den vรคnstra grafen, Det finns tre noder. Dijkstra kommer att kรถras pรฅ grafen sรฅ hรคr:
Steg 1) Startpunkt "1" initieras till noll. De andra noderna kommer att ha oรคndlighet.
Steg 2) Markera noden "1" som besรถkt och inkludera den i den kortaste vรคgen.
Steg 3) Avstรฅndet frรฅn kรคllnod 1 till noderna "2" och "3" รคr satt till oรคndligheten, eftersom den kortaste vรคgen รคnnu inte har berรคknats. Sรฅ varje vรคg som kostar mindre รคn oรคndligheten kommer att lรคggas till den kortaste vรคgen (girig metod).
Steg 4) Uppdaterar avstรฅndet frรฅn kรคllnoden "1" till "2". Den aktuella vikten blir 5 (5 < oรคndligheten). Uppdatera pรฅ liknande sรคtt avstรฅndet frรฅn noden "1" till "3" med vikten 3.
Steg 5) Om vi โโnu kontrollerar de kortaste avstรฅnden frรฅn nod "1", finner vi att 5 รคr det kortaste avstรฅndet fรถr kant 1โ2. Sรฅ nod "2" kommer att markeras som besรถkt. Pรฅ liknande sรคtt kommer nod "3" ocksรฅ att markeras som besรถkt eftersom det kortaste avstรฅndet รคr 3.
Om vi โโemellertid observerar det finns en vรคg 1-3-2 som bara kostar 2. Men Dijkstra visar att frรฅn nod "1" till nod "2" รคr det kortaste avstรฅndet 5. Dijkstra misslyckades alltsรฅ med att berรคkna det kortaste avstรฅndet korrekt. Anledningen รคr att Dijkstra รคr en girig algoritm. Sรฅ nรคr en nod vรคl รคr markerad som besรถkt kommer den inte att omprรถvas, รคven om det kan finnas en kortare vรคg tillgรคnglig. Detta problem uppstรฅr bara nรคr kanterna har negativa kostnader eller negativa viktkanter.
Dijkstra misslyckas med att berรคkna den kortaste vรคgen mellan tvรฅ noder i detta scenario. Som ett resultat har denna algoritm vissa nackdelar. Fรถr att lรถsa detta negativa kantproblem anvรคnds en annan algoritm som kallas "Bellman-Ford-algoritmen". Den algoritmen kan arbeta med negativa kanter.
Dijkstras algoritmkomplexitet
Implementeringen ovan anvรคnde tvรฅ "fรถr"-loopar. Dessa slingor lรถper fรถr antalet hรถrn. Sรฅ, tidskomplexiteten รคr O(Vยฒ)Hรคr รคr termen "O" en notation som ger ett antagande fรถr Dijkstra-algoritmen.
Vi kan lagra grafen med hjรคlp av en "prioritetskรถ". En prioritetskรถ รคr en binรคr heap-datastruktur. Den kommer att vara mer effektiv รคn en 2D-matris. En kant med minimal kostnad kommer att ha hรถg prioritet. Dรฅ kommer tidskomplexiteten att vara O(E log V). Hรคr รคr E antalet kanter och V รคr antalet hรถrn.
Utrymmets komplexitet รคr O(Vยฒ), eftersom vi anvรคnder en nรคrliggande matris (2D-array). Utrymmeskomplexitet kan optimeras med hjรคlp av en angrรคnsande lista eller kรถdatastruktur.















