cards-deck: 100-199_university::111-120_theoretic_cs::111_algorithms_datastructures

Dijkstra Algorithmus

anchored to [[111.00_anchor]]


Overview:

Mit Dijkstra können wir SSSP in einem gewichteten Graphen, welcher positive , nicht negative Kanten aufweist.

Definition:

[!Definition] Intuitive Betrachtung Dijkstra #card Prinzipiell möchten wir uns Schritt für Schritt von unserem Punkt zu unserem Zielpunkt bewegen. Dabei arbeiten wir uns so voran, dass wir mit jeder Iteration immer den bestmöglichen Knoten ( bzw günstigsten) übernehmen möchten. Dabei ist wichtig, dass diese Knoten nur angrenzend sein können. Sie müssen also Nachbarn von den bereits gefundenen Knoten ( die wir dann aufgenommen und evaluiert haben) sein.

Mit dieser Prämisse werden wir uns Schritt für Schritt immer den günstigsten Weg suchen, können dabei aber auch keinen finden, wenn denn kein Weg zwischen existiert ( aber dann wäre die Anwendung auch sinnfrei) ^1704708859613

Der Algorithmus setzt bestimmte Mengen, die wir während des Ablaufes betrachten müssen, voraus. Wir definieren sie folgend:

[!Definition] Dijkstra Voraussetzung welche Mengen brauchen wir? #card Wir starten immer an einem Knoten , welcher als unser Startpunkt deklariert ist Wir werden nun eine Menge und weiter

Intuitiv heißt es also, dass wir eine Menge von Knoten haben, die wir schon kennen. Sie befinden sich in . Jetzt werden wir sukzessive S vergrößern, indem wir einen benachbarten Knoten nehmen ( welcher die geringste Distanz zu unserem Ziel haben soll!) und ihn der Menge hinzufügen. Dabei werden wir immer die derzeitige Distanz als Gewicht des Knotens speichern. So können wir immer das minimum anvisieren! ^1704708859624

| Algorithmus

Unter dieser Betrachtung müssen wir jetzt folgend agieren: wie?, was ist notwendig,um von nach zu kommen? #card Wir vergrößern jetzt nach und nach sukzessive, bis wir , dabei möchten wir immer den besten Pfad in jedem Schritt gehen. Das ganze können wir auch in einem PseudoCode beschreiben:

S = {s}, 
d(s), // Initial-Kosten wird aus dem Startknoten genommen
d'(s) = 0
^1704708859630

S' = OutAdj(s) // also alle **Knoten**, die von unserem Startpunkt erreicht werden können!
for all u in S':
	d'(u) = c(s,u) // wir setzen also die Distanz, um von s nach u ( also alle Knoten, die angrenzend sind) zu kommen gleich mit den Kosten dieses Pfades.
for all u in V\(S' und {s}):
	d'(u) = infinity // wir setzen die Distanz aller Knoten, die wir noch nicht besucht haben, auf unendlich 
	// ( weil wir später immer den kleinsten Knoten heraussuchen werden und es somit ermöglicht wird!)

while (S != V){
	w = min(S')  // wähle den Knoten in der Menge von angrenzenden Knoten, der die geringsten Kosten hat!
	d(w) = d'(w) // wir setzen die Kosten des Knotens auf seinen realen Wert ( weil wir ihn schon besucht haben jetzt)
	S = S und {w} // Knoten ist jetzt bekannt
	S' = S'\{w}  // Knoten muss nicht mehr besucht werden
	
	for all (u in OutAdj(w)){ // wir gehen also alle Nachbarn von dem Knoten e durch
	}
		if (u not in (S und S')):
			S' = S' und u // wenn also der neue Nachbar noch nicht bekannt oder entlang der Grenze ( die mit S' beschrieben wird) verläuft / verfügbar ist
		d'(u) = min(d'(u), d'(w)+c(w,u)) // wir suchen den minimalen Wert für die Distanz
		// wir vergleichen, ob der Pfad, den wir schon haben bis zu u kürzer ist, als die vorhandene Distanz von u selbst
}

| Korrektheit

Wir möchten für die Anwendung von Dijkstra ein Lemma setzen:

[!Definition] Lemma | Korrektheit von Dijkstra warum ist er korrekt? Wie beweisen wir es? #card Wird gewählt, sodass minimal ist ( also die Distanz). dann folgt daraus:

Beweis: Wir können die Aussage folgend beweisen: Sei der derzeit billigste Weg von , mit . Dann können wir jetzt annehmen, dass ein billigerer Weg existiert, welchen wir mit definieren möchten. Dabei befindet sich bei diesem Pfad der erste Knoten . Da es ein billigerer Weg ist, muss gelten: Es gilt jetzt aber auch: denn alle Kantenkosten sind nichtnegativ. Dies führt zu einem Widerspruch! ^1704708859636

Laufzeit:

Die Laufzeit von Dijkstra hängt stark davon ab, wie wir die Menge , sowie die Menge der gespeicherten Distanzen umsetzen. ( denn diese sind wichtig und somit Indikatoren, ob unsere Implementation gut funktionieren wird oder nicht )

[!Important] Implementation von wie sollten wir diese implementieren? #card Man könnte / sollte hierbei als Bitvektoren mit der Länge beschreiben und die Distanz-Werte mit einem Integervektor der Länge ^1704708859643

Daraus lässt sich nun auch die Laufzeit berechnen:

[!Definition] Laufzeit für Dijkstra wovon ist sie stark abhängig? wie durchlaufen wir die Knoten? #card for all -> wir durchlaufen also die gesetzte Adjazenzliste. Wir haben weiterhin eine , wodurch wird bei dieser Operation mit resultieren

Es ergibt sich nun folgende Laufzeit: ^1704708859648

Aber wir können die Laufzeit nochmals verbessern:

[!Important] Verkürzung der Laufzeit auf was benötigen wir dafür? #card Man kann die Minimumssuche in umsetzen, sofern man als einen Heap aufbaut [[111.09_heaps#Running time|consider running time]] -> Dadurch wird das Einfügen, die Minimumssuche und das Löschen in umgesetzt.

Wir müssen hier dennoch imemr -Werte verringern ( was im Heap etwas langsamer war). Aber dennoch geht das gut.

Wir resultieren hiermit mit der Laufzeit von ^1704708859654

Folgerung Geschwindigkeit:

[!Definition] In welcher Zeit können wir einen SSSP in einem nicht-negativen, gerichteten Graphen berechnen? #card Wir können einen Single Source Shortest Path in einem gerichteten Graphen mit nichtnegativen Kantenkosten in folgender Zeit berechnen:

Weiterhin wäre es auch in möglich! ^1704708859661