Forum: PC-Programmierung Dijkstra-Algorithmus-Variation in Javascript


von Ernst H. (Firma: Laboratorium_S1) (ernst_haft)


Lesenswert?

Hallo.

In meinem Letzten Beitrag 
(Beitrag "Javascript Verkehrsleitsystem") wurde mir geraten, 
für das Finden des kürzesten Weges zwischen zwei Punkten den 
A*-Algorithmus zu verwenden.

Nach einigen Recherchen lernte ich jedoch den Dijkstra-Algorithmus 
kennen, der mir nicht nur verständlicher, sondern auch einfacher 
erscheint, da nicht berechnet werden muss, wie wahrscheinlich es ist, 
dass ein bestimmter Pfad eher zum Ziel führt als andere.

Ich fand nach einiger Suche Code für JavaScript, der Programmiersprache, 
in der ich den Algorithmus implementieren möchte, auf folgender Seite:
https://www.tutorialspoint.com/Dijkstra-s-algorithm-in-Javascript

Jedoch gibt dieser die kürzeste Entfernung zu allen weiteren Knoten von 
einem Startknoten aus an. Ich benötige jedoch zum einen die Entfernung 
zu einem bestimmten Knoten, zum anderen möchte ich wissen, welchen Pfad 
das Programm errechnet hat.

Wie müsste ich den Code umschreiben? Wird in der "while 
(!pq.isEmpty())"-Schleife geprüft, ob der Ziel-Knoten schon erreicht 
ist?

Zu Beginn des Programms würde ich ein Array initialisieren ("let pfad = 
[];"), welches ebenfalls ausgegeben wird und den "zu gehenden" Pfad 
angibt.

In welcher Schleife werden dann die Knoten des Pfades diesem Array 
hinzugefügt?

Verzeiht die etwas plumpe Grußformel und Verabschiedung. Was kreative 
Begrüßungen und Verabschiedungen angeht, bin ich (zum Glück?) kein 
Profi.

Viele Grüße und Dank für jede hilfreiche Antwort
Ernst

von Herbert B. (Gast)


Lesenswert?

Ernst H. schrieb:
> Wie müsste ich den Code umschreiben? Wird in der "while
> (!pq.isEmpty())"-Schleife geprüft, ob der Ziel-Knoten schon erreicht
> ist?
https://de.wikipedia.org/wiki/Vorrangwarteschlange

von Sophie T. (sophie_t)


Lesenswert?

1) Du prüfst einfach ab ob aus "pq" dein Zielknoten herausgenommen wird. 
In dem Moment kannst du den Algorithmus vorzeitig terminieren:

direkt nach der Zeile
let minNode = pq.dequeue();

machst du:

if minNode.node == "Zielknoten" { break; }


2) Um den Pfad zu rekonstruieren musst du nur "prev" nutzen.
prev speichert den Vorgängerknoten des kürzesten Pfades. Das heißt du 
fängst beim Zielknoten an prev auszuwerten und hangelst dich so 
rückwärts durch den kürzesten Pfad bis du irgendwann beim Startknoten 
angekommen bist.

Noch ein Hinweis. Dijkstra funktioniert nur mit nichtnegativen (>=0) 
Kantengewichten korrekt (liefert den kürzesten Pfad).

: Bearbeitet durch User
von Sophie T. (sophie_t)


Lesenswert?

In Pseudocode könnte das so aussehen:
1
function reconstruct_path(prev: Array, Startknoten, Zielknoten) {
2
  let curNode = Zielknoten;
3
  let Pfad : Array = [Zielknoten];
4
  
5
  while curNode != Startknoten {
6
    //ist ein Vorgänger für diesen Knoten hinterlegt?
7
    //wenn nicht dann gibt es keinen Pfad vom Start- zum Zielknoten
8
    if curNode != null {
9
      curNode = prev[curNode];
10
      Pfad.push(curNode);
11
    } else {
12
      throw new Exception("Es gibt keinen Pfad vom Startknoten zum Zielknoten");
13
    }
14
  }
15
  
16
  //bei Bedarf den Pfad umdrehen
17
  return Pfad.reverseArray();
18
}

von Sophie T. (sophie_t)


Lesenswert?

Theoretisch reicht es den else Zweig
1
} else {
2
      throw new Exception("Es gibt keinen Pfad vom Startknoten zum Zielknoten");
3
    }

genau einmal für den Zielknoten am Anfang (vor der Schleife) 
auszuführen. Denn wenn dieser Knoten einen Vorgänger hat muss der 
Algorithmus vom Startknoten aus irgendwann dort hingekommen sein. Es 
gibt also einen Pfad. So kann man den Algorithmus etwas optimieren...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.