Informatik · Klasse 11–13 · aktualisiert
Dijkstra-Algorithmus einfach erklärt
Du lernst, wie Dijkstra kürzeste Wege in Graphen mit Gewichten findet, wann er passt und warum negative Kanten ihn stören.
0 von 12 Aufgaben gelöst
Kurz gesagt
Der Dijkstra-Algorithmus berechnet kürzeste Wege von einem Startknoten aus, sofern es keine negativen Kantengewichte gibt. Er besucht den Knoten mit der kleinsten Distanz und verbessert die Distanzen seiner Nachbarn. Über die Vorgänger liest du den Weg ab.
Ein Routenplaner sucht die kürzeste Route zwischen zwei Punkten im Straßennetz. Für solche Aufgaben ist der Dijkstra-Algorithmus ein bekanntes Verfahren. Hier lernst du, wann er passt, wie du ihn von Hand ausführst und wo seine Grenzen liegen.
Deine Lernziele
Hake ab, was du schon kannst. Löst du alle Aufgaben eines Abschnitts, hakt Mela das Ziel für dich ab.
5 Abschnitte
Ein Graph besteht aus Knoten und Kanten. In einem kantengewichteten Graphen trägt jede Kante eine Zahl, zum Beispiel eine Streckenlänge. Der Dijkstra-Algorithmus berechnet einen kürzesten Pfad von einem gegebenen Startknoten zu einem der übrigen Knoten oder zu allen. Das klappt, sofern der Graph keine negativen Kantengewichte enthält.
Ein bekanntes Beispiel sind Routenplaner: Der Graph stellt das Verkehrswegenetz dar, und gesucht ist die kürzeste Route zwischen zwei Punkten. Die Kantengewichte dürfen dabei verschieden sein, später etwa 5 für S–A und 6 für S–B.
Willst du nur den Weg zu einem bestimmten Zielknoten, kannst du abbrechen, sobald der gesuchte Knoten an der Reihe ist. Du musst dann nicht alle Knoten besuchen. In einem unzusammenhängenden ungerichteten Graphen ist der Abstand zu Knoten unendlich, zu denen kein Pfad vom Startknoten aus existiert.
Haben alle Kanten dasselbe Gewicht, genügt für einen kürzesten Pfad schon die Breitensuche. Für Graphen mit negativen Kantengewichten gibt es den Bellman-Ford-Algorithmus, der mit negativen Kantengewichten umgehen kann.
Dijkstra gehört zu den Greedy-Algorithmen. „Greedy“ heißt gierig: Sie bevorzugen in jedem Schritt die momentan aussichtsreichste Teillösung. Anders als manche andere Greedy-Algorithmen berechnet Dijkstra unter der Voraussetzung positiver Kantengewichte eine optimale, also kürzeste Lösung.
Definition
Dijkstra-Algorithmus
Ein Verfahren, das in einem kantengewichteten Graphen kürzeste Pfade von einem Startknoten zu einem oder allen übrigen Knoten berechnet, sofern der Graph keine negativen Kantengewichte enthält.
Merke: Dijkstra passt zu kürzesten Wegen von einem Startknoten in kantengewichteten Graphen ohne negative Kantengewichte, zum Beispiel bei Routenplanern.
Teste dich
Zu jedem Knoten merkst du dir zwei Werte: die Distanz (die bisher kürzeste bekannte Strecke vom Start) und den Vorgänger (den Knoten davor auf diesem Weg).
Anfang: Der Startknoten hat die Distanz 0. Alle anderen Knoten haben die Distanz ∞ (unendlich), ihr Vorgänger ist unbekannt.
Dann wiederholst du, solange es unbesuchte Knoten gibt: Wähle unter den unbesuchten Knoten den mit der kleinsten Distanz und markiere ihn als besucht. Für jeden unbesuchten Nachbarn rechnest du die Gesamtdistanz: Kantengewicht plus die Distanz des gewählten Knotens. Ist dieser Wert kleiner als die gespeicherte Distanz, übernimmst du ihn, und der gewählte Knoten wird Vorgänger des Nachbarn.
Die Distanz eines besuchten Knotens bleibt gespeichert. Die Distanzen noch nicht abgearbeiteter Knoten können sich dagegen noch verringern.
Definition
Relaxierung
Der Schritt, bei dem du eine Distanz aktualisierst, wenn der Weg über den gewählten Knoten kürzer ist. Er heißt auch Update oder Relaxation.
Beispiel: Ungerichteter Graph mit Start S
- 1Kanten: S–A:5, S–B:6, A–B:4, A–C:9, B–C:7, C–D:2, B–D:11
- 2S besuchen (Distanz 0): A = 5 (über S), B = 6 (über S)
- 3A besuchen (kleinste Distanz 5): C = 5 + 9 = 14 (über A). B über A wäre 5 + 4 = 9, nicht kleiner als 6, also keine Änderung.
- 4B besuchen (Distanz 6): C über B wäre 6 + 7 = 13, kleiner als 14, also C = 13 (über B). D = 6 + 11 = 17 (über B).
- 5C besuchen (Distanz 13): D über C wäre 13 + 2 = 15, kleiner als 17, also D = 15 (über C).
- 6D besuchen (Distanz 15): keine Änderung. Endwerte: S 0, A 5, B 6, C 13, D 15.
Teste dich
Beim Ausführen hast du für jeden Knoten einen Vorgänger gespeichert. Den kürzesten Weg zu einem Zielknoten findest du, indem du am Zielknoten beginnst und immer zum Vorgänger springst. Das wiederholst du, solange ein Vorgänger existiert. Der Vorgänger des Startknotens ist null, also nicht vorhanden. Dort hörst du auf.
Jeden gefundenen Knoten schreibst du vorn in die Wegliste. So steht der Weg am Ende vom Start zum Ziel. Die Länge des Wegs ist die Endwert-Distanz des Zielknotens.
Definition
Vorgänger
Der Vorgänger eines Knotens ist der Knoten direkt davor auf dem bisher kürzesten Weg vom Start. Er wird bei einer Relaxierung gesetzt.
Beispiel: Weg zu D im Graphen mit Start S
- 1Vorgänger am Ende: A ← S, B ← S, C ← B, D ← C
- 2Ziel D: Wegliste [D]. Vorgänger von D ist C: [C, D].
- 3Vorgänger von C ist B: [B, C, D]. Vorgänger von B ist S: [S, B, C, D].
- 4S hat keinen Vorgänger, Schluss. Weg: S → B → C → D, Länge 15.
- 5Zum Vergleich: Ziel A hat den Vorgänger S. Weg S → A, Länge 5.
Merke: Vom Ziel aus rückwärts über die Vorgänger gehen und jeden Knoten vorn in die Wegliste einfügen.
Teste dich
Dijkstra ändert eine einmal festgelegte Distanz zum Startknoten nicht mehr. Das ist bei positiven Kantengewichten in Ordnung: Ein später gefundener kürzerer Weg hätte eine kürzere Teilstrecke gehabt, die man früher hätte untersuchen müssen.
Bei negativen Kantengewichten stimmt das nicht mehr. Dann kann jede Teilstrecke für sich eine kürzeste Strecke sein, und trotzdem lässt sich die Gesamtdistanz über einen längeren Teilweg verbessern, wenn eine negative Kante die Weglänge wieder reduziert. Dijkstra hat die Distanz aber schon festgelegt und ändert sie nicht mehr.
Deshalb können negative Kantengewichte zu nicht-optimalen Lösungen führen. Wie das Verfahren im Einzelnen versagt, betrachten wir hier nicht. Für Graphen mit negativen Kantengewichten gibt es den Bellman-Ford-Algorithmus als Alternative.
Definition
Negative Kante
Eine Kante, deren Gewicht eine Zahl kleiner als 0 ist. Sie reduziert die Länge eines Wegs, wenn er über sie läuft.
Merke: Dijkstra legt Distanzen fest und ändert sie nicht mehr. Eine negative Kante kann einen längeren Teilweg nachträglich billiger machen. Das Ergebnis kann dann nicht-optimal sein.
Teste dich
Die Breitensuche durchsucht einen Graphen ausgehend vom Startknoten Level für Level: Zuerst werden alle Knoten bearbeitet, die direkt erreichbar sind, dann die nächste Ebene. Jede durch Breitensuche gefundene Lösung hat den kürzesten Abstand zum Wurzelknoten. Mit Kantengewichten muss das Ergebnis, das am nächsten zum Startknoten liegt, aber nicht notwendigerweise auch das mit den geringsten Pfadkosten sein. Nur wenn alle Kantengewichte gleich sind, ist jede durch Breitensuche gefundene Lösung optimal. Dijkstra rechnet dagegen mit den Gewichten.
Ein Spannbaum ist ein Teilgraph eines ungerichteten Graphen, der ein Baum ist und alle Knoten des Graphen enthält. Das Gewicht eines Graphen ist die Summe seiner Kantengewichte. Ein Spannbaum heißt minimal, wenn kein anderer Spannbaum im selben Graphen ein geringeres Gewicht hat. Einen minimalen Spannbaum berechnest du zum Beispiel mit dem Algorithmus von Kruskal: Du gehst die Kanten nach aufsteigendem Gewicht durch und nimmst jede Kante auf, die mit den bisher gewählten Kanten keinen Kreis bildet.
Die Vorgänger von Dijkstra bilden ebenfalls einen Baum aus kürzesten Pfaden vom Start. Dieser Baum ist aber nicht notwendigerweise minimal. Dijkstra fragt also: „Wie komme ich vom Start am kürzesten zu jedem Knoten?“ Ein minimaler Spannbaum fragt: „Wie verbinde ich alle Knoten mit dem kleinsten Gesamtgewicht?“
| Verfahren | Was es liefert | Wichtig |
|---|---|---|
| Breitensuche | Knoten Level für Level, das Nächstliegende zuerst | Bei gleichen Kantengewichten ist ihr Ergebnis optimal |
| Dijkstra | Kürzeste Wege vom Startknoten | Keine negativen Kantengewichte |
| Kruskal | Minimaler Spannbaum | Kanten nach Gewicht, keine Kreise |
Beispiel: Derselbe Graph: Dijkstra-Baum gegen minimalen Spannbaum
- 1Graph wie oben (Start S). Dijkstra-Baum aus den Vorgängern: S–A, S–B, B–C, C–D. Gewicht 5 + 6 + 7 + 2 = 20.
- 2Kruskal nimmt C–D (2), A–B (4), S–A (5) auf. S–B (6) wird verworfen, weil S und B schon verbunden sind und ein Kreis entstünde.
- 3Dann folgt B–C (7). Gewicht des minimalen Spannbaums: 2 + 4 + 5 + 7 = 18.
- 420 gegen 18: Der Dijkstra-Baum enthält S–B, der Kruskal-Baum nicht. Die Bäume sind verschieden.
Merke: Dijkstra liefert kürzeste Wege vom Start. Ein minimaler Spannbaum liefert das kleinste Gesamtgewicht. Der Dijkstra-Baum ist nicht notwendigerweise minimal.
Teste dich
Alles auf einen Blick
Dijkstra-Algorithmus
Einsatz
Dijkstra berechnet kürzeste Wege von einem Startknoten in kantengewichteten Graphen, sofern es keine negativen Kantengewichte gibt
Ablauf
Wähle den unbesuchten Knoten mit der kleinsten Distanz und verbessere die Distanzen seiner Nachbarn
Relaxierung
Neue Distanz = Distanz des gewählten Knotens plus Kantengewicht. Nur wenn sie kleiner ist, wird sie übernommen
Weg
Vom Ziel aus über die Vorgänger rückwärts gehen
Negative Kanten
Festgelegte Distanzen werden nicht mehr geändert, deshalb kann das Ergebnis nicht-optimal werden
Abgrenzung
Breitensuche geht Ebene für Ebene, ein minimaler Spannbaum hat das kleinste Gesamtgewicht, Dijkstra liefert kürzeste Wege
Musteraufgabe · Schritt für Schritt
Kürzesten Weg von P nach T finden (ausgedachtes Beispiel)
- 1Ungerichteter Graph: P–Q:2, P–R:7, Q–R:3, Q–T:8, R–T:1. Start P, Ziel T.
- 2Anfang: P hat 0, Q, R und T haben ∞.
- 3P besuchen: Q = 0 + 2 = 2 (über P), R = 0 + 7 = 7 (über P).
- 4Q besuchen (kleinste Distanz 2): R über Q wäre 2 + 3 = 5, kleiner als 7, also R = 5 (über Q). T = 2 + 8 = 10 (über Q).
- 5R besuchen (Distanz 5): T über R wäre 5 + 1 = 6, kleiner als 10, also T = 6 (über R).
- 6T ist an der Reihe, du kannst abbrechen. Rückwärts über die Vorgänger: T, R, Q, P.
- 7Weg: P → Q → R → T mit Länge 6. Probe: 2 + 3 + 1 = 6.
Fehler finden
Prüfe die Schritte bei Dijkstra mit Start K (ausgedachtes Beispiel) In einer Zeile steckt ein Fehler. Tippe sie an.
Fehler in Zeile 4Hier fehlt die Distanz des gewählten Knotens: Die neue Distanz ist Kantengewicht plus Distanz von L, also 3 + 3 = 6. Richtig: N = 6 (über L).
Lückentext
Wähl in jeder Lücke das passende Wort und prüf dann deine Antworten.
Dijkstra berechnet kürzeste Wege, sofern der Graph keine Kantengewichte enthält. Von den unbesuchten Knoten wählt er den mit der Distanz. Jeden gefundenen Vorgänger fügst du am der Wegliste ein.
Karteikasten
Erst selbst überlegen, dann umdrehen.
Übung mit Feedback