Dijkstra's Algorithmus
Einführung
Dijkstra’s Algorithmus ermöglicht es den billigsten Weg zwischen Knoten in einem
gewichteten Graphen zu finden. Der Algorithmus ist nach dem niederländischen
Informatiker und Wissenschaftler Edsger W. Dijkstra
benannt, der ihn 1956 entwickelte.
Er findet den kürzesten Weg von einem Startknoten zu allen anderen Knoten im
Graphen. Dies kann einerseits nützlich sein um den kürzesten Weg von einer
Ausgangsstadt zu einer anderen Stadt zu finden oder in der Netzwerktechnik um
die schnellste Verbindung zu einem anderen Computer zu finden, zum Beispiel als
Teil von OPFS (Open Shortest Path First).
Beispiel
Um den Algorithmus einmal graphisch darzustellen und das Verständnis zu vereinfachen hier ein Beispiel:
Gegeben ist folgender Graph:
%%{
init: {
'theme':'dark'
}
}%%
graph LR
Bern((Bern)) <-->|6| Basel((Basel))
Bern <-->|5| Luzern((Luzern))
Bern <-->|19| Lugano((Lugano))
Basel <-->|5| Zürich((Zürich))
Basel <-->|4| Luzern
Zürich <-->|7| Chur((Chur))
Luzern <-->|4| Zürich
Luzern <-->|9| Chur
Luzern <-->|12| Lugano
Lugano <-->|11| Chur
Wenn nun das Ziel ist den kürzesten Weg von Bern nach Chur zu finden muss der Algorithmus herausfinden, wie teuer es ist von Bern zu den anderen Knoten zu gelangen. Dazu beginnt man mit Bern, welches keine Kosten hat, da man dort beginnt, von hier aus können alle direkt Verbunden Knoten erreicht werden. Diese erhalten, dann die bisherigen Kosten plus die Kosten der Kante über welche sie erreicht werden sowie die Information von welchem Knoten aus sie erreicht wurden. Alle so neu gefunden Knoten, werden in eine Liste aufgenommen, damit all deren Verbindungen geprüft werden können. Wird ein Knoten von zwei verschiedenen Pfaden erreicht, so erhält dieser die Kosten welche tiefer sind. Nachdem alle Knoten überprüft wurden können die Kosten für den Knoten Chur sowie alle vorherigen Knoten ausgelesen werden.
In diesem Fall wäre der schnellste Weg von Bern nach Chur über Luzern, dies führt zu Kosten von 14:
%%{
init: {
'theme':'dark'
}
}%%
graph LR
Bern((Bern: 0)) <-->|5| Luzern((Luzern: 5))
Luzern <-->|9| Chur((Chur: 14))
Funktionsweise
Dieser Abschnitt orientiert sich stark an der Beschreibung von Wikipedia:
Dijkstr’s Algorithm > Algorithm
Dijkstra’s Algorithmus benötigt einen Startknoten sowie einen Zielkonten N,
welcher eine Distanz zum Startknoten hat. Der Algorithmus geht dann davon aus
das alle Knoten eine Unendliche Distanz haben und versucht diese zu verbessern.
- Erstelle ein Set aller Knoten, welche noch nicht geprüft wurden.
- Weise jedem Knoten eine Distanz von Startknoten hinzu für den Startknoten ist diese 0 für alle anderen Unendlich, da noch kein Pfad zu diesen gefunden wurde. Während der Ausführung werden diese durch die kürzest gefunden Pfade ersetzt.
- Wähle den Knoten mit der kleinsten endlichen Distanz aus dem Set der noch nicht besuchten Knoten, anfänglich wird dies der Startknoten sein. Falls das Set leer ist oder kein Knoten mit einer endlichen Distanz gefunden wird ist der Algorithmus fertig und es kann mit Schritt 6 fortgefahren werden. Falls nur der Pfad zum Zielknoten relevant ist, kann der Algorithmus auch zu Schritt 6 springen, wenn der jetzige Knoten der Zielknoten ist.
- Für den jetzigen Knoten überprüfe alle Nachbarn, welche noch nicht besucht
wurden und aktualisieren deren Distanz. Dazu muss die neu berechnete Distanz
durch den jetzigen Knoten mit der momentanen Distanz des Nachbarns verglichen
werden, dieser soll die kleiner Distanz erhalten. Das heisst wenn der jetzige
Knoten
Aeine Distanz von 7 hat und die Kante zum NachbarnBeine Länge von 2 hat, so ist die Distanz zuBüberA9 (7 + 2). Ist die momentane Distanz vonBgrösser als 9 soll diese auf 9 gesetzt werden (Der Weg überAist kürzer), andernfalls soll die Distanz beibehalten werden (Der Weg überAist nicht kürzer). - Nachdem alle Nachbarn des jetzigen Knoten überprüft wurden, markiere den
jetzigen Knoten als besucht und entferne ihn aus dem Set der noch nicht
besuchten Knoten. Dadurch wird dieser nicht mehr überprüft, dies ist korrekt,
da die gespeicherte Distanz auf dem Knoten bereits minimal ist (durch Schritt
3 sichergestellt) und deshalb final.
Gehe zurück zu Schritt 3. - Nachdem die Schleife fertig ist (Schritte 3-5) enthalten alle Knoten die kürzeste Distanz vom Startknoten aus.
Pseudocode
Folgend ist ein Pseudocode Beispiel des Algorithmus dieses Benutzt eine priorisierte Warteschlange um die Knoten mit der kleinsten Distanz zu erhalten. Dazu nutzt er eine einfach Optimierung des Algorithmus bei der nicht alle Knoten mit einer Unendlichen Distanz initialisiert werden, sondern neue Knoten nach und nach entdeckt werden.
function dijkstra(start, graph) {
PriorityQueue<Tuple<Number, Node>> queue;
Map<Node, Number> distances;
Map<Node, Number> previous;
distances[start] = 0;
previous[start] = null;
queue.push(Tuple(0, start));
while(!queue.empty()) {
Number distance, Node current = queue.pop();
for(Node neighbor in graph.neighbors(current)) {
Number newDistance = distances + graph.distance(current, neighbor);
if(!distances.contains(neighbor) || newDistance < distances[neighbor]) {
distances[neighbor] = newDistance;
previous[neighbor] = current;
queue.push(Tuple(newDistance, neighbor));
}
}
}
return dist, prev;
}
Ressourcen
Wikipedia - Dijkstr’s Algorithm
Implementierung
Implementation in C++
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <tuple>
#include <vector>
struct Node
{
std::string name;
Node(const std::string& name): name(name) {}
};
struct Edge
{
struct Node *first;
struct Node *second;
int distance;
Edge(struct Node *first, struct Node *second, int distance): first(first), second(second), distance(distance) {}
};
struct Graph
{
std::vector<struct Node *> nodes;
std::vector<struct Edge *> edges;
~Graph()
{
for (auto edge : edges)
delete edge;
}
void addNode(struct Node *node)
{
nodes.push_back(node);
};
void addEdge(struct Node *first, struct Node *second, int distance)
{
struct Edge *edge = new Edge(first, second, distance);
edges.push_back(edge);
};
std::vector<struct Node *> getNeighbors(struct Node *node)
{
std::vector<struct Node *> neighbors;
for (const auto& edge : edges)
{
if (edge->first == node)
{
neighbors.push_back(edge->second);
}
else if (edge->second == node)
{
neighbors.push_back(edge->first);
}
}
return neighbors;
};
int getDistance(struct Node *first, struct Node *second)
{
for (const auto& edge : edges)
{
if ((edge->first == first && edge->second == second) || (edge->first == second && edge->second == first))
{
return edge->distance;
}
}
throw std::runtime_error("No edge found between nodes");
};
};
std::tuple<std::map<struct Node *, int>, std::map<struct Node *, struct Node *>> dijkstras(struct Node *start, Graph *graph)
{
using QueueType = std::tuple<int, struct Node *>;
std::priority_queue<QueueType, std::vector<QueueType>, std::greater<QueueType>> queue;
std::map<struct Node *, int> distances;
std::map<struct Node *, struct Node *> previous;
distances[start] = 0;
previous[start] = nullptr;
queue.push(std::make_tuple(0, start));
do
{
auto [distance, current] = queue.top();
queue.pop();
for (const auto& neighbor : graph->getNeighbors(current))
{
int newDistance = distance + graph->getDistance(current, neighbor);
if (!distances.count(neighbor) || newDistance < distances[neighbor])
{
distances[neighbor] = newDistance;
previous[neighbor] = current;
queue.push(std::make_tuple(newDistance, neighbor));
}
}
} while (!queue.empty());
return std::make_tuple(distances, previous);
}
int main(int argc, char *argv[])
{
Node *Bern = new Node("Bern");
Node *Basel = new Node("Basel");
Node *Luzern = new Node("Luzern");
Node *Lugano = new Node("Lugano");
Node *Zürich = new Node("Zürich");
Node *Chur = new Node("Chur");
Graph *graph = new Graph;
graph->addNode(Bern);
graph->addNode(Basel);
graph->addNode(Luzern);
graph->addNode(Lugano);
graph->addNode(Zürich);
graph->addNode(Chur);
graph->addEdge(Bern, Basel, 6);
graph->addEdge(Bern, Luzern, 5);
graph->addEdge(Bern, Lugano, 19);
graph->addEdge(Basel, Zürich, 5);
graph->addEdge(Basel, Luzern, 4);
graph->addEdge(Luzern, Zürich, 4);
graph->addEdge(Luzern, Chur, 9);
graph->addEdge(Luzern, Lugano, 12);
graph->addEdge(Zürich, Chur, 7);
graph->addEdge(Lugano, Chur, 11);
auto [distances, previous] = dijkstras(Bern, graph);
std::cout << "Distance from Bern to Chur: " << distances[Chur] << std::endl;
delete graph;
delete Bern;
delete Basel;
delete Luzern;
delete Lugano;
delete Zürich;
delete Chur;
return 0;
}
Last updated 20 Juni 2025, 10:57 +0200 .
Was hat dir gefallen?
Was ist schiefgelaufen