Dijkstras Algorithmus mit einer Priority Queue
Implementieren Sie Dijkstra mit heapq, verfolgen Sie die Relaxierungsschritte an einem gewichteten Graphen und lösen Sie cheapest-flights-within-k-stops.
Dijkstras Algorithmus mit einer Priority Queue ist eine kostenlose DSA Interview Prep-Lektion auf CoddyKit. Dies ist Lektion 1 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des DSA Interview Prep-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der DSA Interview Prep-Kurs umfasst insgesamt 4 Lektionen.
Kürzeste Wege in gewichteten Graphen
Dijkstras Algorithmus findet den kürzesten Weg von einem einzelnen Startknoten zu allen anderen Knoten in einem gewichteten Graphen mit nichtnegativen Kantengewichten. Dazu werden die Knoten gierig in der Reihenfolge ihrer aktuell besten bekannten Distanz verarbeitet – stets wird der nächstgelegene noch nicht besuchte Knoten erweitert. Die entscheidende Datenstruktur ist ein Min-Heap (Prioritätswarteschlange), der effizient den Knoten mit der kleinsten Distanz liefert.
Überblick über die Algorithmusschritte
Dijkstras Algorithmus: (1) Initialisieren Sie dist[source] = 0 und dist[all others] = inf. (2) Legen Sie (0, source) in einen Min-Heap. (3) Entfernen Sie den Knoten u mit der kleinsten Distanz. Wenn er bereits mit einer kleineren Distanz besucht wurde, überspringen Sie ihn. (4) Prüfen Sie für jeden Nachbarn v von u: Falls dist[u] + weight(u,v) < dist[v] gilt, aktualisieren Sie dist[v] und legen Sie (dist[v], v) in den Heap. (5) Wiederholen Sie dies, bis der Heap leer ist.
Python-Implementierung mit heapq
Das Python-Modul heapq implementiert einen Min-Heap. Wir stellen den Graphen als Adjazenzliste dar: graph[u] = [(v, weight), ...]. Der Heap speichert Tupel der Form (distance, node). Wir verwenden eine visited-Menge, um veraltete Heap-Einträge zu überspringen – also Einträge, die hinzugefügt wurden, bevor ein besserer Weg gefunden wurde.
import heapq
def dijkstra(graph, source):
n = len(graph)
dist = [float('inf')] * n
dist[source] = 0
heap = [(0, source)] # (distance, node)
visited = set()
while heap:
d, u = heapq.heappop(heap)
if u in visited:
continue
visited.add(u)
for v, weight in graph[u]:
if dist[u] + weight < dist[v]:
dist[v] = dist[u] + weight
heapq.heappush(heap, (dist[v], v))
return distDurchgearbeitetes Beispiel
Betrachten Sie einen Graphen mit 5 Knoten und den Kanten: 0→1 (4), 0→2 (1), 2→1 (2), 1→3 (1), 2→3 (5), 3→4 (3). Die kürzesten Wege vom Knoten 0 sind: zu 1 über 0→2→1 mit den Kosten 3, zu 2 mit den Kosten 1, zu 3 über 0→2→1→3 mit den Kosten 4 und zu 4 über 0→2→1→3→4 mit den Kosten 7. Dijkstra findet alle diese Wege in einem Durchlauf, nicht nur den Weg zu einem einzelnen Zielknoten.
import heapq
def dijkstra(graph, source):
dist = [float('inf')] * len(graph)
dist[source] = 0
heap = [(0, source)]
visited = set()
while heap:
d, u = heapq.heappop(heap)
if u in visited:
continue
visited.add(u)
for v, w in graph[u]:
if dist[u] + w < dist[v]:
dist[v] = dist[u] + w
heapq.heappush(heap, (dist[v], v))
return dist
graph = [
[(1,4),(2,1)], # 0
[(3,1)], # 1
[(1,2),(3,5)], # 2
[(4,3)], # 3
[] # 4
]
print(dijkstra(graph, 0)) # [0, 3, 1, 4, 7]Warum Dijkstra bei negativen Gewichten scheitert
Die Korrektheit von Dijkstra beruht darauf, dass die Distanz eines Knotens endgültig ist, sobald er aus dem Min-Heap entnommen wird. Das gilt nur, wenn die Kantengewichte nichtnegativ sind. Bei einer negativen Kante u→v mit dem Gewicht -5 könnten wir nach dem Besuch von v einen kürzeren Pfad über u finden – aber v ist bereits als besucht markiert. Eine einzige negative Kante kann alle nachfolgenden Distanzberechnungen ungültig machen.
Günstigste Flüge mit höchstens K Zwischenstopps (LeetCode 787)
Dieses Problem fügt eine Einschränkung hinzu: höchstens k Zwischenstopps. Der standardmäßige Dijkstra-Algorithmus verarbeitet die Anzahl der Schritte nicht direkt. Lösung: Erweitern Sie den Zustand zu (cost, node, stops_remaining). Verwenden Sie Dijkstra mit diesem 3-Tupel oder Bellman-Ford mit k+1 Relaxierungsdurchläufen. Der modifizierte Dijkstra-Algorithmus stoppt, sobald stops_remaining 0 erreicht, und verhindert so weitere Sprünge.
import heapq
from collections import defaultdict
def findCheapestPrice(n, flights, src, dst, k):
graph = defaultdict(list)
for u, v, w in flights:
graph[u].append((v, w))
heap = [(0, src, k + 1)] # (cost, node, hops_left)
visited = {} # node -> min hops_left seen at this cost level
while heap:
cost, node, hops = heapq.heappop(heap)
if node == dst:
return cost
if hops == 0:
continue
if visited.get(node, 0) >= hops:
continue
visited[node] = hops
for nxt, w in graph[node]:
heapq.heappush(heap, (cost + w, nxt, hops - 1))
return -1
print(findCheapestPrice(4,[[0,1,100],[1,2,100],[0,2,500]],0,2,1)) # 200Analyse der Zeitkomplexität
Mit einem Binär-Heap läuft Dijkstra in O((V + E) log V) Zeit: Jeder Knoten wird einmal entnommen (V Entnahmen), jede Kante kann einen Push auslösen (E Pushes), und jede Heap-Operation kostet O(log V). Mit einem Fibonacci-Heap verbessert sich die Schranke auf O(E + V log V), aber Python's heapq ist ein Binär-Heap. Für dünn besetzte Graphen (E ≈ V) hat die Binär-Heap-Version die Komplexität O(V log V); für dichte Graphen (E ≈ V²) beträgt sie O(V² log V).
Den kürzesten Pfad rekonstruieren
Um den tatsächlichen Pfad und nicht nur die Distanzen zu ermitteln, verwalten Sie ein prev-Array: Setzen Sie beim Aktualisieren von dist[v] den Wert prev[v] = u. Nach Abschluss des Algorithmus rekonstruieren Sie den Pfad von der Quelle zum Ziel, indem Sie rückwärts zurückverfolgen: Beginnen Sie bei dst, folgen Sie den prev-Zeigern bis zu source und kehren Sie anschließend die Reihenfolge des Ergebnisses um.
import heapq
def dijkstra_path(graph, source, target):
n = len(graph)
dist = [float('inf')] * n
prev = [-1] * n
dist[source] = 0
heap = [(0, source)]
visited = set()
while heap:
d, u = heapq.heappop(heap)
if u in visited: continue
visited.add(u)
for v, w in graph[u]:
if dist[u] + w < dist[v]:
dist[v] = dist[u] + w
prev[v] = u
heapq.heappush(heap, (dist[v], v))
# Reconstruct
path, node = [], target
while node != -1:
path.append(node)
node = prev[node]
return dist[target], path[::-1]Ein Dict für dünn besetzte Graphen verwenden
Wenn Knoten Strings oder nicht zusammenhängende Ganzzahlen sind, verwenden Sie eine defaultdict(list) für die Adjazenzliste und ein gewöhnliches dict für die Distanzen. Dies ist in LeetCode-Problemen wie Network Delay Time üblich, bei denen die Knoten mit 1 bis n beschriftet sind. Denken Sie daran, dist = {node: inf for node in all_nodes} zu verwenden und nach dem Algorithmus auf nicht erreichbare Knoten zu prüfen.
import heapq
from collections import defaultdict
def networkDelayTime(times, n, k):
graph = defaultdict(list)
for u, v, w in times:
graph[u].append((v, w))
dist = {i: float('inf') for i in range(1, n+1)}
dist[k] = 0
heap = [(0, k)]
while heap:
d, u = heapq.heappop(heap)
if d > dist[u]: continue
for v, w in graph[u]:
if dist[u] + w < dist[v]:
dist[v] = dist[u] + w
heapq.heappush(heap, (dist[v], v))
ans = max(dist.values())
return ans if ans < float('inf') else -1
print(networkDelayTime([[2,1,1],[2,3,1],[3,4,1]], 4, 2)) # 2Vergleich mit BFS für ungewichtete Graphen
Für ungewichtete Graphen findet BFS kürzeste Pfade in O(V + E) – schneller als Dijkstras O((V+E) log V). Dijkstra verallgemeinert BFS auf gewichtete Graphen, indem eine Prioritätswarteschlange anstelle einer gewöhnlichen FIFO-Warteschlange verwendet wird. Wenn alle Kantengewichte gleich sind, wird Dijkstra zu BFS. Verwenden Sie BFS für ungewichtete Graphen, Dijkstra für nichtnegative Gewichte und Bellman-Ford für negative Gewichte.
Dijkstra mit Decrease-Key-Optimierung
Der Dijkstra-Algorithmus aus Lehrbüchern verwendet eine Prioritätswarteschlange mit decrease-key: Wenn sich die Distanz eines Knotens verbessert, wird seine Priorität direkt aktualisiert. Dafür wäre ein Fibonacci-Heap erforderlich, um O(E + V log V) zu erreichen, die Implementierung ist jedoch schwierig. Beim in Interviews verwendeten Ansatz der Lazy Deletion wird stattdessen ein neuer Eintrag eingefügt und veraltete Entnahmen werden übersprungen – einfacher, bei nur konstantem Mehraufwand. In Python ist Lazy Deletion mit heapq die übliche Implementierung in Interviews.
Schnelltest
Testen Sie Ihr Verständnis der Konzepte aus Data Structures & Algorithms — Coding Interview Prep in dieser Lektion.
Zusammenfassung der Lektion
In dieser Lektion haben Sie gelernt: Dijkstra verwendet einen Min-Heap, um Knoten in der Reihenfolge ihrer aktuell besten Distanz gierig zu verarbeiten, läuft in O((V+E) log V) Zeit und scheitert bei Kanten mit negativen Gewichten und veraltete Heap-Einträge werden durch die Prüfung einer Menge besuchter Knoten beim Entnehmen behandelt. Als Nächstes behandeln wir Bellman-Ford, der negative Gewichte durch n-1 Relaxierungsdurchläufe verarbeitet.
Häufig gestellte Fragen
Ist die Lektion „Dijkstras Algorithmus mit einer Priority Queue“ kostenlos?
Ja — der vollständige Text von „Dijkstras Algorithmus mit einer Priority Queue“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des DSA Interview Prep-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der DSA Interview Prep-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Dijkstras Algorithmus mit einer Priority Queue“?
Implementieren Sie Dijkstra mit heapq, verfolgen Sie die Relaxierungsschritte an einem gewichteten Graphen und lösen Sie cheapest-flights-within-k-stops. Du übst DSA Interview Prep mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um DSA Interview Prep zu starten?
Keine Vorkenntnisse erforderlich. DSA Interview Prep auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 1 von 4.
Wie lange dauert die Lektion „Dijkstras Algorithmus mit einer Priority Queue“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser DSA Interview Prep-Lektion Code schreiben und ausführen?
Ja. Jede DSA Interview Prep-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Dijkstras Algorithmus mit einer Priority Queue
- Bellman-Ford und negative Zyklen
- Floyd-Warshall: Kürzeste Wege zwischen allen Knotenpaaren
- Network Delay Time und Pfadrekonstruktion