From 2834a065b3032fbe60f8f11eefe330e5ba66eded Mon Sep 17 00:00:00 2001 From: trekhleb <3000285+trekhleb@users.noreply.github.com> Date: Sun, 9 Nov 2025 20:40:25 +0100 Subject: [PATCH] Add Dijkstra algorithm illustrations and explanations --- src/algorithms/graph/dijkstra/README.de-DE.md | 161 +++++++++++++++++ src/algorithms/graph/dijkstra/README.es-ES.md | 150 ++++++++++++++++ src/algorithms/graph/dijkstra/README.fr-FR.md | 156 +++++++++++++++++ src/algorithms/graph/dijkstra/README.he-IL.md | 160 +++++++++++++++++ src/algorithms/graph/dijkstra/README.ja-JP.md | 165 ++++++++++++++++++ src/algorithms/graph/dijkstra/README.ko-KR.md | 156 ++++++++++++++++- src/algorithms/graph/dijkstra/README.md | 9 +- src/algorithms/graph/dijkstra/README.uk-UA.md | 10 +- src/algorithms/graph/dijkstra/README.zh-CN.md | 155 ++++++++++++++++ src/algorithms/graph/dijkstra/README.zh-TW.md | 161 +++++++++++++++++ 10 files changed, 1272 insertions(+), 11 deletions(-) create mode 100644 src/algorithms/graph/dijkstra/README.de-DE.md create mode 100644 src/algorithms/graph/dijkstra/README.es-ES.md create mode 100644 src/algorithms/graph/dijkstra/README.fr-FR.md create mode 100644 src/algorithms/graph/dijkstra/README.he-IL.md create mode 100644 src/algorithms/graph/dijkstra/README.ja-JP.md create mode 100644 src/algorithms/graph/dijkstra/README.zh-CN.md create mode 100644 src/algorithms/graph/dijkstra/README.zh-TW.md diff --git a/src/algorithms/graph/dijkstra/README.de-DE.md b/src/algorithms/graph/dijkstra/README.de-DE.md new file mode 100644 index 0000000000..59c80546e5 --- /dev/null +++ b/src/algorithms/graph/dijkstra/README.de-DE.md @@ -0,0 +1,161 @@ +# Dijkstra-Algorithmus + +_Lies dies in anderen Sprachen:_ +[_English_](README.md), +[_한국어_](README.ko-KR.md), +[_日本語_](README.ja-JP.md), +[_简体中文_](README.zh-CN.md), +[_繁體中文_](README.zh-TW.md), +[_Українська_](README.uk-UA.md), +[_Español_](README.es-ES.md), +[_Français_](README.fr-FR.md), +[_Deutsch_](README.de-DE.md), +[_עברית_](README.he-IL.md) + +Der Dijkstra-Algorithmus ist ein Algorithmus zur Bestimmung der kürzesten Wege zwischen Knoten in einem Graphen, der beispielsweise Straßennetze darstellen kann. + +Der Algorithmus existiert in vielen Varianten; die ursprüngliche Version von Dijkstra fand den kürzesten Weg zwischen zwei Knoten, aber eine gebräuchlichere Variante fixiert einen einzelnen Knoten als „Quellknoten“ und findet die kürzesten Wege von dieser Quelle zu allen anderen Knoten im Graphen. Das Ergebnis ist ein sogenannter „kürzester-Wege-Baum“ (Shortest-Path Tree). + +![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif) + +Der Dijkstra-Algorithmus findet den kürzesten Weg zwischen `a` und `b`. +Er wählt den unbesuchten Knoten mit der kleinsten aktuellen Entfernung, +berechnet die Distanzen zu jedem unbesuchten Nachbarn über diesen Knoten +und aktualisiert die Entfernung des Nachbarn, wenn sie kleiner ist. +Nachdem alle Nachbarn überprüft wurden, wird der Knoten als besucht markiert (rot dargestellt). + +## Praktische Anwendungen des Dijkstra-Algorithmus + +- GPS- und Navigationssysteme +- Optimierung von Routen im öffentlichen Verkehr und im Flugverkehr +- Internet-Routing (OSPF-, IS-IS-Protokolle) +- Optimierung von Netzwerkverkehr und Latenzzeiten +- Pfadsuche in Computerspielen (kürzester Weg auf Karten) +- Routenoptimierung in Logistik und Lieferketten +- Planung von Transport- und Versorgungsnetzen + +## Schritt-für-Schritt-Beispiel des Dijkstra-Algorithmus + +Nehmen wir an, wir haben einen gewichteten Graphen, bei dem jede Kante eine Distanz zwischen Knoten hat. +Zum Beispiel beträgt die Entfernung zwischen Knoten `A` und `B` `7 Meter` (oder kurz `7m`). + +Der Algorithmus verwendet eine [Prioritätswarteschlange](../../../data-structures/priority-queue/), +um immer den nächsten unbesuchten Knoten mit der kleinsten Entfernung vom Startknoten zu entnehmen. + +Der Startknoten hat per Definition eine Entfernung von `0m` zu sich selbst. +Wir beginnen also mit diesem Knoten – er ist der einzige in der Prioritätswarteschlange zu Beginn. + +Die restlichen Knoten werden während der Graphdurchquerung (beim Besuchen der Nachbarn) später hinzugefügt. + +![Dijkstra step 1](./images/dijkstra-01.png) + +Jeder Nachbar des aus der Warteschlange entnommenen Knotens wird überprüft, um die Entfernung vom Startpunkt zu berechnen. +Zum Beispiel: Die Entfernung von `A` nach `B` beträgt `0m + 7m = 7m`. + +Jedes Mal, wenn wir einen neuen, noch nicht gesehenen Nachbarn besuchen, fügen wir ihn der Prioritätswarteschlange hinzu, wobei die Priorität die Distanz zum Startknoten ist. + +Der Knoten `B` wird mit der Priorität 7m in die Warteschlange eingefügt, um später besucht zu werden. + +![Dijkstra step 2](./images/dijkstra-02.png) + +Als Nächstes besuchen wir den Nachbarn `C` von `A`. +Die Entfernung vom Startknoten `A` zu `C` beträgt `0m + 9m = 9m`. + +Der Knoten `C` wird ebenfalls in die Prioritätswarteschlange eingefügt. + +![Dijkstra step 3](./images/dijkstra-03.png) + +Dasselbe gilt für den Knoten `F`. +Die aktuelle Entfernung von `A` zu `F` ist `0m + 14m = 14m`. + +`F` wird in die Warteschlange eingefügt, um später besucht zu werden. + +![Dijkstra step 4](./images/dijkstra-04.png) + +Nachdem alle Nachbarn des aktuellen Knotens überprüft wurden, wird dieser Knoten zur `visited`-Menge hinzugefügt. +Solche Knoten werden in den nächsten Schritten nicht erneut besucht. + +Nun entnehmen wir aus der Prioritätswarteschlange den nächsten Knoten mit der kürzesten Distanz zur Quelle und beginnen, seine Nachbarn zu besuchen. + +![Dijkstra step 5](./images/dijkstra-05.png) + +Wenn der Knoten, den wir besuchen (in diesem Fall `C`), bereits in der Warteschlange ist, +bedeutet das, dass die Distanz zu ihm bereits von einem anderen Pfad (`A → C`) berechnet wurde. +Wenn die aktuelle Distanz (über `A → B → C`) kürzer ist, aktualisieren wir den Wert in der Warteschlange. +Ist sie länger, bleibt sie unverändert. + +Beim Besuch von `C` über `B` (`A → B → C`) beträgt die Distanz `7m + 10m = 17m`. +Dies ist länger als die bereits gespeicherte Distanz `9m` für `A → C`. +Daher ignorieren wir diesen längeren Pfad. + +![Dijkstra step 6](./images/dijkstra-06.png) + +Wir besuchen einen weiteren Nachbarn von `B`, nämlich `D`. +Die Entfernung zu `D` beträgt `7m + 15m = 22m`. +Da `D` noch nicht besucht wurde und nicht in der Warteschlange ist, fügen wir ihn mit der Priorität `22m` hinzu. + +![Dijkstra step 7](./images/dijkstra-07.png) + +An diesem Punkt wurden alle Nachbarn von `B` besucht, daher wird `B` zur `visited`-Menge hinzugefügt. +Als Nächstes entnehmen wir aus der Warteschlange den Knoten, der dem Ursprung am nächsten ist. + +![Dijkstra step 8](./images/dijkstra-08.png) + +Wir besuchen die unbesuchten Nachbarn von `C`. +Die Distanz zu `F` über `C` (`A → C → F`) beträgt `9m + 2m = 11m`. +Dies ist kürzer als der bisher gespeicherte Weg `A → F` von `14m`. +In diesem Fall aktualisieren wir die Distanz zu `F` auf `11m` und passen ihre Priorität in der Warteschlange an. +Wir haben einen kürzeren Weg zu `F` gefunden. + +![Dijkstra step 9](./images/dijkstra-09.png) + +Dasselbe gilt für `D`. +Wir haben einen kürzeren Pfad zu `D` gefunden – der Weg `A → C → D` ist kürzer als `A → B → D`. +Die Distanz wird von `22m` auf `20m` aktualisiert. + +![Dijkstra step 10](./images/dijkstra-10.png) + +Alle Nachbarn von `C` wurden besucht, daher fügen wir `C` zur `visited`-Menge hinzu. +Wir entnehmen den nächsten Knoten aus der Warteschlange, der `F` ist. + +![Dijkstra step 11](./images/dijkstra-11.png) + +Wir notieren die Distanz zu `E` als `11m + 9m = 20m`. + +![Dijkstra step 12](./images/dijkstra-12.png) + +Wir fügen `F` zur `visited`-Menge hinzu und entnehmen den nächsten Knoten `D`. + +![Dijkstra step 13](./images/dijkstra-13.png) + +Die Distanz zu `E` über `D` ist `20m + 6m = 26m`. +Das ist länger als die bereits berechnete Distanz von `20m` über `F`. +Daher verwerfen wir diesen längeren Weg. + +![Dijkstra step 14](./images/dijkstra-14.png) + +Der Knoten `D` ist jetzt besucht. + +![Dijkstra step 15](./images/dijkstra-15.png) + +Auch der Knoten `E` wurde besucht. +Die Durchquerung des Graphen ist abgeschlossen. + +![Dijkstra step 16](./images/dijkstra-16.png) + +Nun kennen wir die kürzesten Distanzen von jedem Knoten ausgehend vom Startknoten `A`. + +In der Praxis speichert man während der Berechnungen zusätzlich die `previousVertices` (vorherige Knoten), +um die genaue Reihenfolge der Knoten im kürzesten Pfad rekonstruieren zu können. + +Zum Beispiel ist der kürzeste Pfad von `A` nach `E`: `A → C → F → E`. + +## Beispielimplementierung + +- [dijkstra.js](./dijkstra.js) + +## Quellen + +- [Wikipedia](https://de.wikipedia.org/wiki/Dijkstra-Algorithmus) +- [YouTube – Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) +- [YouTube – Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) diff --git a/src/algorithms/graph/dijkstra/README.es-ES.md b/src/algorithms/graph/dijkstra/README.es-ES.md new file mode 100644 index 0000000000..06261ca280 --- /dev/null +++ b/src/algorithms/graph/dijkstra/README.es-ES.md @@ -0,0 +1,150 @@ +# Algoritmo de Dijkstra + +_Lee esto en otros idiomas:_ +[_English_](README.md), +[_한국어_](README.ko-KR.md), +[_日本語_](README.ja-JP.md), +[_简体中文_](README.zh-CN.md), +[_繁體中文_](README.zh-TW.md), +[_Українська_](README.uk-UA.md), +[_Español_](README.es-ES.md), +[_Français_](README.fr-FR.md), +[_Deutsch_](README.de-DE.md), +[_עברית_](README.he-IL.md) + +El algoritmo de Dijkstra es un algoritmo para encontrar los caminos más cortos entre nodos en un grafo, que puede representar, por ejemplo, redes de carreteras. + +El algoritmo existe en muchas variantes; la versión original de Dijkstra encontraba el camino más corto entre dos nodos, pero una variante más común fija un solo nodo como el "nodo fuente" y encuentra los caminos más cortos desde la fuente hacia todos los demás nodos del grafo, produciendo un árbol de caminos más cortos. + +![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif) + +El algoritmo de Dijkstra busca el camino más corto entre `a` y `b`. +Selecciona el vértice no visitado con la menor distancia, calcula la distancia a través de él hacia cada vecino no visitado, y actualiza la distancia del vecino si es menor. Marca el vértice como visitado (en rojo) cuando se han procesado todos sus vecinos. + +## Aplicaciones prácticas del algoritmo de Dijkstra + +- Sistemas GPS / navegación +- Optimización de rutas de transporte público y aerolíneas +- Enrutamiento de Internet (protocolos OSPF, IS-IS) +- Optimización del tráfico y la latencia en redes +- Búsqueda de caminos en videojuegos (camino más corto en mapas) +- Optimización de rutas de logística y entrega +- Diseño de redes de transporte y cadenas de suministro + +## Ejemplo paso a paso del algoritmo de Dijkstra + +Supongamos que tenemos un grafo ponderado de nodos, donde cada arista tiene un valor de distancia entre los nodos. Por ejemplo, la distancia entre el nodo `A` y el nodo `B` es de `7 metros` (o simplemente `7m` para abreviar). + +El algoritmo utiliza una [cola de prioridad](../../../data-structures/priority-queue/) para obtener siempre el siguiente vértice no visitado con la menor distancia desde el nodo de origen. + +El nodo inicial, por definición, tiene una distancia de `0m` desde sí mismo. Así que comenzamos con él — el único nodo en la cola de prioridad al inicio. + +El resto de los nodos se agregará a la cola de prioridad más tarde, durante la exploración del grafo (al visitar los vecinos). + +![Dijkstra step 1](./images/dijkstra-01.png) + +Cada vecino del nodo extraído de la cola se recorre para calcular la distancia desde el origen. +Por ejemplo, la distancia de `A` a `B` es `0m + 7m = 7m`. + +Cada vez que visitamos un vecino aún no visto, lo agregamos a la cola de prioridad, donde la prioridad es la distancia al nodo vecino desde el origen. + +El nodo `B` se agrega a la cola de prioridad mínima para ser recorrido más adelante. + +![Dijkstra step 2](./images/dijkstra-02.png) + +Visitamos el siguiente vecino `C` del nodo `A`. +La distancia desde el nodo de origen `A` hasta `C` es `0m + 9m = 9m`. + +El nodo `C` se agrega a la cola de prioridad mínima para recorrerlo más tarde. + +![Dijkstra step 3](./images/dijkstra-03.png) + +Lo mismo ocurre con el nodo `F`. +La distancia actual de `A` a `F` es `0m + 14m = 14m`. + +El nodo `F` se agrega a la cola de prioridad mínima para ser recorrido más adelante. + +![Dijkstra step 4](./images/dijkstra-04.png) + +Una vez que se han revisado todos los vecinos del nodo actual, este se agrega al conjunto `visited`. No queremos volver a visitar estos nodos más adelante. + +Ahora extraemos de la cola el siguiente nodo más cercano al origen (el de menor distancia) y comenzamos a visitar sus vecinos. + +![Dijkstra step 5](./images/dijkstra-05.png) + +Si el nodo que estamos visitando (en este caso, `C`) ya está en la cola, significa que ya habíamos calculado la distancia hacia él, pero desde otro camino (`A → C`). +Si la distancia actual (desde el camino `A → B → C`) es menor que la calculada antes, actualizamos la distancia (en la cola de prioridad) con la más corta, ya que buscamos los caminos más cortos. +Si la distancia es mayor, la dejamos como está. + +Al visitar el nodo `C` a través de `B` (camino `A → B → C`), vemos que la distancia sería `7m + 10m = 17m`. +Esto es más largo que la distancia ya registrada de `9m` para el camino `A → C`. En estos casos, simplemente ignoramos la distancia más larga. + +![Dijkstra step 6](./images/dijkstra-06.png) + +Visitamos otro vecino de `B`, que es `D`. +La distancia hacia `D` es `7m + 15m = 22m`. +Como aún no hemos visitado `D` y no está en la cola de prioridad, la agregamos con una prioridad (distancia) de `22m`. + +![Dijkstra step 7](./images/dijkstra-07.png) + +En este punto, todos los vecinos de `B` han sido recorridos, así que agregamos `B` al conjunto `visited`. +Luego extraemos el nodo más cercano al origen desde la cola de prioridad. + +![Dijkstra step 8](./images/dijkstra-08.png) + +Recorremos los vecinos no visitados del nodo `C`. +La distancia hacia `F` a través de `C` (camino `A → C → F`) es `9m + 2m = 11m`. +Esto es más corto que el camino anterior `A → F` de `14m`. +En este caso, actualizamos la distancia de `F` a `11m` y su prioridad en la cola. Hemos encontrado un camino más corto hacia `F`. + +![Dijkstra step 9](./images/dijkstra-09.png) + +Lo mismo ocurre con `D`. +Hemos encontrado un camino más corto hacia `D`, donde `A → C → D` es más corto que `A → B → D`. +Actualizamos la distancia de `22m` a `20m`. + +![Dijkstra step 10](./images/dijkstra-10.png) + +Todos los vecinos de `C` han sido recorridos, así que podemos agregar `C` al conjunto `visited`. +Extraemos de la cola el siguiente nodo más cercano, que es `F`. + +![Dijkstra step 11](./images/dijkstra-11.png) + +Registramos la distancia hacia `E` como `11m + 9m = 20m`. + +![Dijkstra step 12](./images/dijkstra-12.png) + +Agregamos el nodo `F` al conjunto `visited` y extraemos el siguiente nodo más cercano, `D`. + +![Dijkstra step 13](./images/dijkstra-13.png) + +La distancia hacia `E` a través de `D` es `20m + 6m = 26m`. +Esto es más largo que la distancia ya calculada hacia `E` desde `F`, que es `20m`. +Podemos descartar la distancia más larga. + +![Dijkstra step 14](./images/dijkstra-14.png) + +El nodo `D` ahora está visitado. + +![Dijkstra step 15](./images/dijkstra-15.png) + +El nodo `E` también ha sido visitado. +Hemos terminado de recorrer el grafo. + +![Dijkstra step 16](./images/dijkstra-16.png) + +Ahora conocemos las distancias más cortas desde el nodo inicial `A` hacia cada nodo. + +En la práctica, durante el cálculo de distancias también registramos los `previousVertices` (vértices anteriores) para poder mostrar la secuencia exacta de nodos que forman el camino más corto. + +Por ejemplo, el camino más corto de `A` a `E` es `A → C → F → E`. + +## Ejemplo de implementación + +- [dijkstra.js](./dijkstra.js) + +## Referencias + +- [Wikipedia](https://es.wikipedia.org/wiki/Algoritmo_de_Dijkstra) +- [YouTube - Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) +- [YouTube - Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) diff --git a/src/algorithms/graph/dijkstra/README.fr-FR.md b/src/algorithms/graph/dijkstra/README.fr-FR.md new file mode 100644 index 0000000000..45808e3afb --- /dev/null +++ b/src/algorithms/graph/dijkstra/README.fr-FR.md @@ -0,0 +1,156 @@ +# Algorithme de Dijkstra + +_Lire ceci dans d’autres langues :_ +[_English_](README.md), +[_한국어_](README.ko-KR.md), +[_日本語_](README.ja-JP.md), +[_简体中文_](README.zh-CN.md), +[_繁體中文_](README.zh-TW.md), +[_Українська_](README.uk-UA.md), +[_Español_](README.es-ES.md), +[_Français_](README.fr-FR.md), +[_Deutsch_](README.de-DE.md), +[_עברית_](README.he-IL.md) + +L’algorithme de Dijkstra est un algorithme permettant de trouver les plus courts chemins entre des nœuds dans un graphe, pouvant représenter, par exemple, un réseau routier. + +Il existe plusieurs variantes de cet algorithme. La version originale de Dijkstra trouvait le plus court chemin entre deux nœuds, mais la version la plus courante fixe un seul nœud comme « nœud source » et calcule les plus courts chemins de cette source vers tous les autres nœuds du graphe, produisant ainsi un arbre des plus courts chemins. + +![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif) + +L’algorithme de Dijkstra trouve le plus court chemin entre `a` et `b`. +Il sélectionne le sommet non visité avec la plus petite distance, calcule la distance à travers ce sommet vers chacun de ses voisins non visités, et met à jour la distance du voisin si celle-ci est plus courte. +Le sommet est ensuite marqué comme visité (en rouge) lorsque tous ses voisins ont été traités. + +## Applications pratiques de l’algorithme de Dijkstra + +- Systèmes GPS / navigation +- Optimisation des itinéraires de transport public et d’avions +- Routage Internet (protocoles OSPF, IS-IS) +- Optimisation du trafic et de la latence réseau +- Recherche de chemin dans les jeux vidéo (chemin le plus court sur une carte) +- Optimisation des itinéraires de livraison et de logistique +- Conception de réseaux de transport et de chaînes d’approvisionnement + +## Exemple pas à pas de l’algorithme de Dijkstra + +Supposons que nous ayons un graphe pondéré de nœuds, où chaque arête possède une distance entre deux nœuds. +Par exemple, la distance entre le nœud `A` et le nœud `B` est de `7 mètres` (ou simplement `7m`). + +L’algorithme utilise une [file de priorité](../../../data-structures/priority-queue/) pour toujours extraire le prochain sommet non visité ayant la plus petite distance depuis le nœud d’origine. + +Le nœud de départ, par définition, a une distance de `0m` depuis lui-même. +Nous commençons donc avec ce nœud, le seul présent dans la file de priorité au départ. + +Les autres nœuds seront ajoutés à la file de priorité plus tard, pendant la traversée du graphe (en visitant les voisins). + +![Dijkstra step 1](./images/dijkstra-01.png) + +Chaque voisin du nœud extrait de la file est parcouru afin de calculer la distance à partir du nœud d’origine. +Par exemple, la distance de `A` à `B` est `0m + 7m = 7m`. + +Chaque fois qu’un voisin encore non visité est découvert, il est ajouté à la file de priorité, la priorité correspondant à la distance depuis le nœud d’origine. + +Le nœud `B` est ajouté à la file de priorité minimale pour être traité plus tard. + +![Dijkstra step 2](./images/dijkstra-02.png) + +Nous visitons le voisin suivant, `C`, du nœud `A`. +La distance depuis le nœud d’origine `A` vers `C` est `0m + 9m = 9m`. + +Le nœud `C` est ajouté à la file de priorité minimale pour être parcouru ultérieurement. + +![Dijkstra step 3](./images/dijkstra-03.png) + +Même chose pour le nœud `F`. +La distance actuelle de `A` à `F` est `0m + 14m = 14m`. + +Le nœud `F` est ajouté à la file de priorité minimale pour être visité plus tard. + +![Dijkstra step 4](./images/dijkstra-04.png) + +Une fois que tous les voisins du nœud actuel ont été examinés, ce nœud est ajouté à l’ensemble `visited`. +Nous ne souhaitons plus revisiter ces nœuds lors des prochaines itérations. + +Nous extrayons maintenant de la file le nœud le plus proche de la source (celui ayant la plus courte distance) et commençons à visiter ses voisins. + +![Dijkstra step 5](./images/dijkstra-05.png) + +Si le nœud que nous visitons (dans ce cas, `C`) est déjà présent dans la file, cela signifie que sa distance a déjà été calculée via un autre chemin (`A → C`). +Si la nouvelle distance (depuis le chemin `A → B → C`) est plus courte, nous mettons à jour la distance dans la file de priorité. +Si elle est plus longue, nous la laissons telle quelle. + +En visitant le nœud `C` via `B` (chemin `A → B → C`), nous trouvons que la distance est `7m + 10m = 17m`. +Ceci est plus long que la distance enregistrée de `9m` pour le chemin `A → C`. +Dans ce cas, nous ignorons simplement cette distance plus longue. + +![Dijkstra step 6](./images/dijkstra-06.png) + +Nous visitons un autre voisin de `B`, à savoir `D`. +La distance vers `D` est `7m + 15m = 22m`. +Comme `D` n’a pas encore été visité et n’est pas dans la file, nous l’ajoutons avec une priorité (distance) de `22m`. + +![Dijkstra step 7](./images/dijkstra-07.png) + +À ce stade, tous les voisins de `B` ont été parcourus, donc nous ajoutons `B` à l’ensemble `visited`. +Ensuite, nous extrayons de la file le nœud le plus proche du nœud d’origine. + +![Dijkstra step 8](./images/dijkstra-08.png) + +Nous parcourons les voisins non visités du nœud `C`. +La distance vers `F` via `C` (chemin `A → C → F`) est `9m + 2m = 11m`. +C’est plus court que la distance précédemment enregistrée de `14m` pour le chemin `A → F`. +Nous mettons donc à jour la distance de `F` à `11m` et ajustons sa priorité dans la file. +Nous venons de trouver un chemin plus court vers `F`. + +![Dijkstra step 9](./images/dijkstra-09.png) + +Même chose pour `D`. +Nous avons trouvé un chemin plus court vers `D` : `A → C → D` est plus court que `A → B → D`. +Nous mettons à jour la distance de `22m` à `20m`. + +![Dijkstra step 10](./images/dijkstra-10.png) + +Tous les voisins de `C` ont été parcourus, donc nous pouvons ajouter `C` à l’ensemble `visited`. +Nous extrayons maintenant de la file le prochain nœud le plus proche, `F`. + +![Dijkstra step 11](./images/dijkstra-11.png) + +Nous enregistrons la distance vers `E` comme `11m + 9m = 20m`. + +![Dijkstra step 12](./images/dijkstra-12.png) + +Nous ajoutons `F` à l’ensemble `visited` et extrayons ensuite `D`, le prochain nœud le plus proche. + +![Dijkstra step 13](./images/dijkstra-13.png) + +La distance vers `E` via `D` est `20m + 6m = 26m`. +C’est plus long que la distance déjà calculée depuis `F` (`20m`). +Nous pouvons donc ignorer cette distance plus longue. + +![Dijkstra step 14](./images/dijkstra-14.png) + +Le nœud `D` est maintenant visité. + +![Dijkstra step 15](./images/dijkstra-15.png) + +Le nœud `E` est maintenant visité également. +La traversée du graphe est terminée. + +![Dijkstra step 16](./images/dijkstra-16.png) + +Nous connaissons maintenant les distances les plus courtes vers chaque nœud depuis le nœud de départ `A`. + +En pratique, pendant le calcul des distances, on enregistre également les `previousVertices` (nœuds précédents) pour pouvoir reconstruire la séquence exacte des nœuds qui forment le chemin le plus court. + +Par exemple, le chemin le plus court de `A` à `E` est `A → C → F → E`. + +## Exemple d’implémentation + +- [dijkstra.js](./dijkstra.js) + +## Références + +- [Wikipédia](https://fr.wikipedia.org/wiki/Algorithme_de_Dijkstra) +- [YouTube - Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) +- [YouTube - Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) diff --git a/src/algorithms/graph/dijkstra/README.he-IL.md b/src/algorithms/graph/dijkstra/README.he-IL.md new file mode 100644 index 0000000000..0ff1942f98 --- /dev/null +++ b/src/algorithms/graph/dijkstra/README.he-IL.md @@ -0,0 +1,160 @@ +# אלגוריתם דייקסטרה (Dijkstra's Algorithm) + +_קרא בשפות אחרות:_ +[_English_](README.md), +[_한국어_](README.ko-KR.md), +[_日本語_](README.ja-JP.md), +[_简体中文_](README.zh-CN.md), +[_繁體中文_](README.zh-TW.md), +[_Українська_](README.uk-UA.md), +[_Español_](README.es-ES.md), +[_Français_](README.fr-FR.md), +[_Deutsch_](README.de-DE.md), +[_עברית_](README.he-IL.md) + +אלגוריתם דייקסטרה הוא אלגוריתם למציאת המסלולים הקצרים ביותר בין צמתים בגרף, שיכול לייצג למשל רשת כבישים. + +לאלגוריתם יש מספר גרסאות; הגרסה המקורית של דייקסטרה מצאה את המסלול הקצר ביותר בין שני צמתים, אך גרסה נפוצה יותר קובעת צומת אחד כ"צומת מקור" ומוצאת את המסלולים הקצרים ביותר ממנו לכל שאר הצמתים בגרף, וכך נוצרת עץ מסלולים קצרים (Shortest-Path Tree). + +![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif) + +אלגוריתם דייקסטרה למציאת המסלול הקצר ביותר בין `a` ל־`b`. +הוא בוחר את הצומת שלא ביקרו בו שעד כה יש לו את המרחק הקטן ביותר, +מחשב את המרחק דרכו לכל שכן שלא ביקרו בו, +ומעדכן את המרחק אם נמצא מסלול קצר יותר. +כאשר מסיימים לבדוק את כל השכנים, מסמנים את הצומת כ"ביקור הושלם" (אדום). + +## שימושים מעשיים של אלגוריתם דייקסטרה + +- מערכות GPS / ניווט +- אופטימיזציה של מסלולי תחבורה ציבורית וטיסות +- ניתוב באינטרנט (פרוטוקולים OSPF, IS-IS) +- אופטימיזציה של תעבורת רשת וזמני השהיה +- חיפוש מסלולים במשחקים (המסלול הקצר ביותר במפה) +- אופטימיזציה של מסלולי משלוחים ולוגיסטיקה +- תכנון רשתות תחבורה ושרשראות אספקה + +## דוגמה שלב-אחר-שלב לאלגוריתם דייקסטרה + +נניח שיש לנו גרף משוקלל של צמתים, שבו לכל קשת יש ערך מרחק בין צמתים. +לדוגמה, המרחק בין הצומת `A` לצומת `B` הוא `7 מטרים` (או בקיצור `7m`). + +האלגוריתם משתמש ב[תור עדיפויות](../../../data-structures/priority-queue/) כדי תמיד לבחור את הצומת שלא ביקרו בו עם המרחק הקטן ביותר מהצומת ההתחלתי. + +צומת ההתחלה, על פי ההגדרה, נמצא במרחק `0m` מעצמו. +לכן מתחילים ממנו — הצומת היחיד בתור העדיפויות בתחילת התהליך. + +שאר הצמתים יתווספו לתור במהלך המעבר בגרף (בעת ביקור בשכנים). + +![Dijkstra step 1](./images/dijkstra-01.png) + +כל שכן של הצומת שנשלף מהתור נבדק כדי לחשב את המרחק אליו מהמקור. +לדוגמה, המרחק מ־`A` ל־`B` הוא `0m + 7m = 7m`. + +בכל פעם שמבקרים שכן חדש שטרם נבדק, מוסיפים אותו לתור העדיפויות, +כאשר העדיפות נקבעת לפי המרחק מהמקור. + +הצומת `B` נוסף לתור העדיפויות המינימלי כדי לעבור עליו מאוחר יותר. + +![Dijkstra step 2](./images/dijkstra-02.png) + +מבקרים את השכן הבא של `A`, שהוא `C`. +המרחק מ־`A` ל־`C` הוא `0m + 9m = 9m`. + +הצומת `C` נוסף גם הוא לתור העדיפויות. + +![Dijkstra step 3](./images/dijkstra-03.png) + +כנ"ל לגבי הצומת `F`. +המרחק הנוכחי מ־`A` ל־`F` הוא `0m + 14m = 14m`. + +`F` נוסף לתור כדי לעבור עליו בהמשך. + +![Dijkstra step 4](./images/dijkstra-04.png) + +לאחר שכל השכנים של הצומת הנוכחי נבדקו, מוסיפים אותו לקבוצת `visited`. +אין צורך לבקר בו שוב. + +כעת נשלוף מהתור את הצומת הקרוב ביותר למקור (בעל המרחק הקצר ביותר) +ונתחיל לבקר את שכניו. + +![Dijkstra step 5](./images/dijkstra-05.png) + +אם הצומת שבו אנו מבקרים (למשל `C`) כבר נמצא בתור, +המשמעות היא שכבר חישבנו את המרחק אליו, אבל ממסלול אחר (`A → C`). +אם המרחק הנוכחי (דרך המסלול `A → B → C`) קצר יותר, נעדכן אותו; +אם ארוך יותר — נשאיר אותו כפי שהוא. + +לדוגמה, בעת ביקור ב־`C` דרך `B` (`A → B → C`), המרחק הוא `7m + 10m = 17m`. +זה ארוך יותר מהמרחק שכבר נרשם (`9m`), ולכן אין עדכון. + +![Dijkstra step 6](./images/dijkstra-06.png) + +מבקרים שכן נוסף של `B`, שהוא `D`. +המרחק ל־`D` הוא `7m + 15m = 22m`. +מכיוון שטרם ביקרנו ב־`D` והוא אינו בתור, נוסיף אותו עם עדיפות (מרחק) של `22m`. + +![Dijkstra step 7](./images/dijkstra-07.png) + +בשלב זה כל שכניו של `B` נבדקו, ולכן נוסיף את `B` לקבוצת `visited`. +לאחר מכן נשלוף את הצומת הקרוב ביותר למקור מהתור. + +![Dijkstra step 8](./images/dijkstra-08.png) + +מבקרים את השכנים הלא-מבוקרים של `C`. +המרחק ל־`F` דרך `C` (המסלול `A → C → F`) הוא `9m + 2m = 11m`. +זה קצר יותר מהמרחק שנרשם קודם (`14m` ל־`A → F`). +לכן נעדכן את המרחק של `F` ל־`11m` ואת העדיפות שלו בתור. +מצאנו מסלול קצר יותר ל־`F`. + +![Dijkstra step 9](./images/dijkstra-09.png) + +אותו הדבר עבור `D`. +מצאנו מסלול קצר יותר — `A → C → D` קצר מ־`A → B → D`. +נעדכן את המרחק מ־`22m` ל־`20m`. + +![Dijkstra step 10](./images/dijkstra-10.png) + +כל שכניו של `C` נבדקו, ולכן נוסיף את `C` ל־`visited`. +נשלוף מהתור את הצומת הקרוב ביותר הבא — `F`. + +![Dijkstra step 11](./images/dijkstra-11.png) + +נרשום את המרחק ל־`E` כ־`11m + 9m = 20m`. + +![Dijkstra step 12](./images/dijkstra-12.png) + +נוסיף את `F` לקבוצת `visited`, ונשלוף את הצומת הקרוב הבא — `D`. + +![Dijkstra step 13](./images/dijkstra-13.png) + +המרחק ל־`E` דרך `D` הוא `20m + 6m = 26m`. +זה ארוך יותר מהמרחק שכבר חושב (`20m` דרך `F`), ולכן נתעלם ממנו. + +![Dijkstra step 14](./images/dijkstra-14.png) + +הצומת `D` כעת סומן כ"ביקור הושלם". + +![Dijkstra step 15](./images/dijkstra-15.png) + +הצומת `E` גם סומן כ"ביקור הושלם". +סיימנו את המעבר בגרף. + +![Dijkstra step 16](./images/dijkstra-16.png) + +כעת אנו יודעים את המרחקים הקצרים ביותר מכל צומת לנקודת ההתחלה `A`. + +בפועל, במהלך חישוב המרחקים שומרים גם את ה־`previousVertices` (הצמתים הקודמים) +כדי שנוכל לשחזר את הרצף המדויק של הצמתים שמרכיבים את המסלול הקצר ביותר. + +לדוגמה, המסלול הקצר מ־`A` ל־`E` הוא `A → C → F → E`. + +## דוגמת מימוש + +- [dijkstra.js](./dijkstra.js) + +## מקורות + +- [ויקיפדיה](https://he.wikipedia.org/wiki/אלגוריתם_דייקסטרה) +- [YouTube – Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) +- [YouTube – Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) diff --git a/src/algorithms/graph/dijkstra/README.ja-JP.md b/src/algorithms/graph/dijkstra/README.ja-JP.md new file mode 100644 index 0000000000..648460c906 --- /dev/null +++ b/src/algorithms/graph/dijkstra/README.ja-JP.md @@ -0,0 +1,165 @@ +# ダイクストラ法 (Dijkstra's Algorithm) + +_他の言語で読む:_ +[_English_](README.md), +[_한국어_](README.ko-KR.md), +[_日本語_](README.ja-JP.md), +[_简体中文_](README.zh-CN.md), +[_繁體中文_](README.zh-TW.md), +[_Українська_](README.uk-UA.md), +[_Español_](README.es-ES.md), +[_Français_](README.fr-FR.md), +[_Deutsch_](README.de-DE.md), +[_עברית_](README.he-IL.md) + +ダイクストラ法は、グラフ内のノード間の最短経路を見つけるためのアルゴリズムです。 +例えば道路網などを表すことができます。 + +このアルゴリズムにはいくつかのバリエーションがあります。 +ダイクストラの元々の手法は、2つのノード間の最短経路を求めるものでしたが、 +より一般的なバージョンでは、1つのノードを「始点(ソース)」として固定し、 +その始点から他のすべてのノードまでの最短経路を求め、最短経路木(shortest-path tree)を生成します。 + +![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif) + +`a` から `b` への最短経路を見つけるダイクストラ法。 +訪問していないノードの中で最も距離の短いノードを選び、 +そのノードを経由して未訪問の隣接ノードへの距離を計算し、 +もし短ければその距離を更新します。 +すべての隣接ノードを処理したら、そのノードを訪問済み(赤色)としてマークします。 + +## ダイクストラ法の実用例 + +- GPS / ナビゲーションシステム +- 公共交通機関や航空路線の最適化 +- インターネットルーティング(OSPF、IS-IS プロトコル) +- ネットワークトラフィックとレイテンシーの最適化 +- ゲームにおける経路探索(マップ上の最短経路) +- 物流および配送ルートの最適化 +- サプライチェーンや交通ネットワーク設計 + +## ダイクストラ法のステップごとの例 + +重み付きグラフがあり、各辺にはノード間の距離が設定されています。 +たとえば、ノード `A` とノード `B` の距離が `7m` であるとします。 + +このアルゴリズムは、[優先度付きキュー](../../../data-structures/priority-queue/)を使用し、 +常に始点から最も近い未訪問ノードを取り出します。 + +始点ノードは自分自身からの距離が `0m` なので、 +最初にキューに入っているのはこのノードだけです。 + +他のノードは、グラフ探索中(隣接ノードを訪問する際)に後でキューに追加されます。 + +![Dijkstra step 1](./images/dijkstra-01.png) + +キューから取り出したノードの各隣接ノードについて、始点からの距離を計算します。 +たとえば、`A` から `B` までの距離は `0m + 7m = 7m` です。 + +初めて訪れる隣接ノードは、始点からの距離を優先度としてキューに追加されます。 + +ノード `B` は、後で探索するために最小優先度キューに追加されます。 + +![Dijkstra step 2](./images/dijkstra-02.png) + +次に、ノード `A` のもう一つの隣接ノード `C` を訪問します。 +始点 `A` から `C` までの距離は `0m + 9m = 9m` です。 + +ノード `C` も最小優先度キューに追加されます。 + +![Dijkstra step 3](./images/dijkstra-03.png) + +同様に、ノード `F` の場合、始点 `A` からの距離は `0m + 14m = 14m` です。 + +ノード `F` も後で探索するためにキューに追加します。 + +![Dijkstra step 4](./images/dijkstra-04.png) + +現在のノードのすべての隣接ノードを確認した後、 +そのノードを `visited` セットに追加します。 +このノードは今後再訪しません。 + +次に、始点から最も近いノードをキューから取り出し、 +その隣接ノードを訪問します。 + +![Dijkstra step 5](./images/dijkstra-05.png) + +訪問中のノード(この場合は `C`)がすでにキューに存在する場合、 +それは別の経路(`A → C`)からすでに距離を計算したことを意味します。 +もし今回の経路(`A → B → C`)を通る距離が短ければ更新し、 +長ければそのままにします。 + +たとえば、`B` 経由で `C` に行くと (`A → B → C`)、距離は `7m + 10m = 17m` です。 +これは既に記録されている距離 `9m` より長いので、更新しません。 + +![Dijkstra step 6](./images/dijkstra-06.png) + +次に、`B` のもう一つの隣接ノード `D` を訪問します。 +距離は `7m + 15m = 22m` です。 +`D` はまだ訪問されておらず、キューにもないため、 +距離 `22m` の優先度でキューに追加します。 + +![Dijkstra step 7](./images/dijkstra-07.png) + +この時点で `B` のすべての隣接ノードを訪問したので、`B` を `visited` に追加します。 +次に、始点に最も近いノードをキューから取り出します。 + +![Dijkstra step 8](./images/dijkstra-08.png) + +ノード `C` の未訪問の隣接ノードを探索します。 +経路 `A → C → F` を通る `F` までの距離は `9m + 2m = 11m` です。 +これは以前の `A → F` の距離 `14m` より短いので、 +`F` の距離を `11m` に更新し、キューの優先度を変更します。 +これでより短い経路が見つかりました。 + +![Dijkstra step 9](./images/dijkstra-09.png) + +`D` についても同様です。 +経路 `A → C → D` は `A → B → D` より短いため、 +距離を `22m` から `20m` に更新します。 + +![Dijkstra step 10](./images/dijkstra-10.png) + +`C` のすべての隣接ノードを訪問したので、`C` を `visited` に追加し、 +次に最も近いノード `F` をキューから取り出します。 + +![Dijkstra step 11](./images/dijkstra-11.png) + +`E` への距離を `11m + 9m = 20m` として記録します。 + +![Dijkstra step 12](./images/dijkstra-12.png) + +`F` を `visited` に追加し、次に最も近い `D` を取り出します。 + +![Dijkstra step 13](./images/dijkstra-13.png) + +`D` 経由で `E` に行く距離は `20m + 6m = 26m` です。 +これはすでに `F` 経由の距離 `20m` より長いため、無視します。 + +![Dijkstra step 14](./images/dijkstra-14.png) + +ノード `D` が訪問されました。 + +![Dijkstra step 15](./images/dijkstra-15.png) + +ノード `E` も訪問されました。 +グラフ探索が完了しました。 + +![Dijkstra step 16](./images/dijkstra-16.png) + +これで、始点ノード `A` から各ノードへの最短距離がわかりました。 + +実際には、距離計算の際に各ノードの `previousVertices`(直前のノード)も記録し、 +最短経路の正確な経路を再構築できるようにします。 + +例えば、`A` から `E` への最短経路は `A → C → F → E` です。 + +## 実装例 + +- [dijkstra.js](./dijkstra.js) + +## 参考文献 + +- [ウィキペディア](https://ja.wikipedia.org/wiki/ダイクストラ法) +- [YouTube - Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) +- [YouTube - Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) diff --git a/src/algorithms/graph/dijkstra/README.ko-KR.md b/src/algorithms/graph/dijkstra/README.ko-KR.md index e2595bbe23..1fca16981a 100644 --- a/src/algorithms/graph/dijkstra/README.ko-KR.md +++ b/src/algorithms/graph/dijkstra/README.ko-KR.md @@ -1,16 +1,154 @@ -# 다익스트라 알고리즘(Dijkstra's algorithm) +# 다익스트라 알고리즘 (Dijkstra's Algorithm) -다익스트라 알고리즘은 도로 네트워크 등을 나타낼 수 있는 그래프에서 노드 간의 최단 경로를 찾는 알고리즘입니다. +_다른 언어로 읽기:_ +[_English_](README.md), +[_한국어_](README.ko-KR.md), +[_日本語_](README.ja-JP.md), +[_简体中文_](README.zh-CN.md), +[_繁體中文_](README.zh-TW.md), +[_Українська_](README.uk-UA.md), +[_Español_](README.es-ES.md), +[_Français_](README.fr-FR.md), +[_Deutsch_](README.de-DE.md), +[_עברית_](README.he-IL.md) -이 알고리즘은 다양한 형태로 존재합니다. 다익스트라의 원래 형태는 두 노드 간의 최단 경로를 찾았지만, 더 일반적인 형태는 단일 노드를 "소스"노드로 수정하고 그래프의 소스에서 다른 모든 노드까지의 최단 경로를 찾아 최단 경로 트리(shortest-path tree)를 생성합니다. +다익스트라 알고리즘은 그래프의 노드 간 최단 경로를 찾는 알고리즘으로, 예를 들어 도로망을 표현할 수 있습니다. + +이 알고리즘에는 여러 변형이 있습니다. 다익스트라의 원래 알고리즘은 두 노드 간의 최단 경로를 찾았지만, 더 일반적인 변형은 하나의 노드를 "출발점(source)"으로 고정하고 그 노드로부터 다른 모든 노드까지의 최단 경로를 찾습니다. 이 과정을 통해 최단 경로 트리(shortest-path tree)가 만들어집니다. ![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif) -`a`와 `b` 사이의 최단 경로를 찾는 다익스트라 알고리즘입니다. -가장 낮은 거리를 가지며 방문하지 않은 정점(vertex)를 선택하고, 이를 통해 방문하지 않은 각 이웃까지의 거리를 계산하며, 더 작은 경우 이웃의 거리를 업데이트합니다. 이웃에 대한 작업을 마치면 방문한 것으로 표시(빨간색으로 변경)합니다. +다익스트라 알고리즘은 `a`에서 `b`로 가는 최단 경로를 찾습니다. +아직 방문하지 않은 노드 중 가장 짧은 거리를 가진 노드를 선택하고, +그 노드를 통해 이웃 노드로 가는 거리를 계산하여 +더 짧은 경로가 있으면 업데이트합니다. +모든 이웃을 확인하면 해당 노드를 방문 완료(빨간색으로 표시)로 처리합니다. + +## 다익스트라 알고리즘의 실제 활용 사례 + +- GPS / 내비게이션 시스템 +- 대중교통 및 항공 노선 최적화 +- 인터넷 라우팅 (OSPF, IS-IS 프로토콜) +- 네트워크 트래픽 및 지연 시간 최적화 +- 게임에서의 경로 탐색 (지도상의 최단 경로) +- 물류 및 배송 경로 최적화 +- 공급망 및 교통 네트워크 설계 + +## 단계별 다익스트라 알고리즘 예제 + +가중치가 있는 그래프가 있다고 가정합시다. 각 간선에는 노드 간의 거리 값이 있습니다. 예를 들어, 노드 `A`와 `B` 사이의 거리가 `7m`라고 하겠습니다. + +이 알고리즘은 항상 출발 노드로부터 가장 짧은 거리를 가진 방문하지 않은 노드를 꺼내기 위해 [우선순위 큐](../../../data-structures/priority-queue/)를 사용합니다. + +출발 노드는 자기 자신으로부터의 거리가 `0m`이므로, 우선순위 큐에는 처음에 이 노드만 포함되어 있습니다. + +다른 노드들은 그래프 탐색 중(이웃 노드를 방문할 때) 나중에 우선순위 큐에 추가됩니다. + +![Dijkstra step 1](./images/dijkstra-01.png) + +큐에서 꺼낸 노드의 각 이웃을 순회하면서 출발 노드로부터의 거리를 계산합니다. +예를 들어, `A`에서 `B`까지의 거리는 `0m + 7m = 7m`입니다. + +아직 방문하지 않은 이웃을 처음 방문하면, 출발 노드로부터의 거리를 우선순위로 하여 우선순위 큐에 추가합니다. + +`B` 노드는 나중에 탐색하기 위해 최소 우선순위 큐에 추가됩니다. + +![Dijkstra step 2](./images/dijkstra-02.png) + +다음으로 `A`의 또 다른 이웃 `C`를 방문합니다. +출발 노드 `A`에서 `C`까지의 거리는 `0m + 9m = 9m`입니다. + +`C` 노드는 이후 탐색을 위해 우선순위 큐에 추가됩니다. + +![Dijkstra step 3](./images/dijkstra-03.png) + +`F` 노드도 동일합니다. +`A`에서 `F`까지의 거리는 `0m + 14m = 14m`입니다. + +`F` 노드는 나중에 탐색하기 위해 우선순위 큐에 추가됩니다. + +![Dijkstra step 4](./images/dijkstra-04.png) + +현재 노드의 모든 이웃을 확인한 후에는 이 노드를 `visited` 집합에 추가합니다. +이후에는 이 노드를 다시 방문하지 않습니다. + +이제 큐에서 출발점으로부터 가장 가까운 노드를 꺼내 그 이웃들을 방문합니다. + +![Dijkstra step 5](./images/dijkstra-05.png) + +방문하려는 노드(`C`)가 이미 큐에 있다면, 이전에 다른 경로(`A → C`)를 통해 계산된 거리 정보가 있다는 뜻입니다. +만약 현재 경로(`A → B → C`)를 통한 거리가 이전 거리보다 짧으면, 큐의 값을 업데이트합니다. +그렇지 않으면 변경하지 않습니다. + +예를 들어 `B`를 통해 `C`를 방문할 때(`A → B → C`), 거리는 `7m + 10m = 17m`입니다. +이는 이미 기록된 거리 `9m`보다 길기 때문에 업데이트하지 않습니다. + +![Dijkstra step 6](./images/dijkstra-06.png) + +`B`의 또 다른 이웃인 `D`를 방문합니다. +`D`까지의 거리는 `7m + 15m = 22m`입니다. +아직 방문하지 않았고 큐에도 없으므로, 우선순위 `22m`으로 큐에 추가합니다. + +![Dijkstra step 7](./images/dijkstra-07.png) + +이 시점에서 `B`의 모든 이웃을 방문했으므로, `B`를 `visited` 집합에 추가합니다. +이제 큐에서 출발점에 가장 가까운 노드를 꺼냅니다. + +![Dijkstra step 8](./images/dijkstra-08.png) + +`C`의 방문하지 않은 이웃들을 탐색합니다. +`C`를 통해 `F`로 가는 경로(`A → C → F`)의 거리는 `9m + 2m = 11m`입니다. +이는 기존의 `A → F` 거리 `14m`보다 짧습니다. +따라서 `F`의 거리를 `11m`로 업데이트하고 큐의 우선순위를 갱신합니다. +더 짧은 경로를 찾았습니다. + +![Dijkstra step 9](./images/dijkstra-09.png) + +`D`도 마찬가지입니다. +`A → C → D` 경로가 `A → B → D`보다 짧으므로, `22m`을 `20m`으로 업데이트합니다. + +![Dijkstra step 10](./images/dijkstra-10.png) + +`C`의 모든 이웃을 방문했으므로 `C`를 `visited`에 추가하고, +큐에서 다음으로 가까운 노드 `F`를 꺼냅니다. + +![Dijkstra step 11](./images/dijkstra-11.png) + +`E`까지의 거리를 `11m + 9m = 20m`으로 기록합니다. + +![Dijkstra step 12](./images/dijkstra-12.png) + +`F`를 `visited`에 추가하고, 다음으로 가까운 `D`를 꺼냅니다. + +![Dijkstra step 13](./images/dijkstra-13.png) + +`D`를 통해 `E`로 가는 거리는 `20m + 6m = 26m`입니다. +이는 이미 계산된 `20m`보다 길기 때문에 무시합니다. + +![Dijkstra step 14](./images/dijkstra-14.png) + +`D` 노드가 방문 완료되었습니다. + +![Dijkstra step 15](./images/dijkstra-15.png) + +`E` 노드도 방문 완료되었습니다. +그래프 탐색이 끝났습니다. + +![Dijkstra step 16](./images/dijkstra-16.png) + +이제 출발 노드 `A`로부터 각 노드까지의 최단 거리를 알 수 있습니다. + +실제로는 거리 계산 중 각 노드의 `previousVertices`(이전 노드)를 함께 저장하여 +최단 경로를 복원할 수 있습니다. + +예를 들어, `A`에서 `E`로 가는 최단 경로는 `A → C → F → E`입니다. + +## 구현 예시 + +- [dijkstra.js](./dijkstra.js) -## 참조 +## 참고 자료 -- [Wikipedia](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm) -- [On YouTube by Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) -- [On YouTube by Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) +- [위키백과](https://ko.wikipedia.org/wiki/다익스트라_알고리즘) +- [YouTube - Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) +- [YouTube - Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) diff --git a/src/algorithms/graph/dijkstra/README.md b/src/algorithms/graph/dijkstra/README.md index 91cde7908b..c5dd44a46a 100644 --- a/src/algorithms/graph/dijkstra/README.md +++ b/src/algorithms/graph/dijkstra/README.md @@ -2,7 +2,14 @@ _Read this in other languages:_ [_한국어_](README.ko-KR.md), -[_Українська_](README.uk-UA.md) +[_日本語_](README.ja-JP.md), +[_简体中文_](README.zh-CN.md), +[_繁體中文_](README.zh-TW.md), +[_Українська_](README.uk-UA.md), +[_Español_](README.es-ES.md), +[_Français_](README.fr-FR.md), +[_Deutsch_](README.de-DE.md), +[_עברית_](README.he-IL.md) Dijkstra's algorithm is an algorithm for finding the shortest paths between nodes in a graph, which may represent, for example, diff --git a/src/algorithms/graph/dijkstra/README.uk-UA.md b/src/algorithms/graph/dijkstra/README.uk-UA.md index 0b901b5b0b..fc2436db08 100644 --- a/src/algorithms/graph/dijkstra/README.uk-UA.md +++ b/src/algorithms/graph/dijkstra/README.uk-UA.md @@ -2,7 +2,15 @@ _Читайте іншими мовами:_ [_English_](README.md), -[_한국어_](README.ko-KR.md) +[_한국어_](README.ko-KR.md), +[_日本語_](README.ja-JP.md), +[_简体中文_](README.zh-CN.md), +[_繁體中文_](README.zh-TW.md), +[_Українська_](README.uk-UA.md), +[_Español_](README.es-ES.md), +[_Français_](README.fr-FR.md), +[_Deutsch_](README.de-DE.md), +[_עברית_](README.he-IL.md) Алгоритм Дейкстри — це алгоритм пошуку найкоротших шляхів між вершинами графа, який може представляти, наприклад, дорожню мережу. diff --git a/src/algorithms/graph/dijkstra/README.zh-CN.md b/src/algorithms/graph/dijkstra/README.zh-CN.md new file mode 100644 index 0000000000..382a9dee05 --- /dev/null +++ b/src/algorithms/graph/dijkstra/README.zh-CN.md @@ -0,0 +1,155 @@ +# Dijkstra 算法 + +_阅读其他语言版本:_ +[_English_](README.md), +[_한국어_](README.ko-KR.md), +[_日本語_](README.ja-JP.md), +[_简体中文_](README.zh-CN.md), +[_繁體中文_](README.zh-TW.md), +[_Українська_](README.uk-UA.md), +[_Español_](README.es-ES.md), +[_Français_](README.fr-FR.md), +[_Deutsch_](README.de-DE.md), +[_עברית_](README.he-IL.md) + +Dijkstra 算法是一种用于在图中查找节点之间最短路径的算法,例如,它可以用于表示道路网络。 + +该算法有许多变体;Dijkstra 的原始版本用于查找两个节点之间的最短路径,但更常见的变体是将一个节点固定为“源节点”,并计算从该源节点到图中所有其他节点的最短路径,从而生成最短路径树。 + +![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif) + +Dijkstra 算法用于查找从 `a` 到 `b` 的最短路径。 +它选择未访问的距离最小的节点,计算通过它到每个未访问邻居的距离, +如果更短,则更新邻居的距离。 +当该节点的所有邻居都被处理完后,将其标记为已访问(红色)。 + +## Dijkstra 算法的实际应用 + +- GPS / 导航系统 +- 公共交通和航线优化 +- 互联网路由(OSPF、IS-IS 协议) +- 网络流量与延迟优化 +- 游戏路径寻路(地图上的最短路径) +- 物流与配送路线优化 +- 供应链与交通网络设计 + +## Dijkstra 算法逐步示例 + +假设我们有一个带权图,每条边表示节点之间的距离。 +例如,节点 `A` 和节点 `B` 之间的距离是 `7 米`(简称 `7m`)。 + +算法使用 [优先队列](../../../data-structures/priority-queue/) 来始终提取离起始节点距离最短的未访问节点。 + +起始节点与自身的距离定义为 `0m`。因此我们从它开始,这是优先队列中的唯一节点。 + +在遍历图的过程中(访问邻居节点时),其余节点会逐渐被添加到优先队列中。 + +![Dijkstra step 1](./images/dijkstra-01.png) + +从队列中取出的节点的每个邻居都会被遍历,以计算从起点到该邻居的距离。 +例如,从 `A` 到 `B` 的距离为 `0m + 7m = 7m`。 + +每次访问尚未访问的邻居时,将其加入优先队列,优先级为从起点到该节点的距离。 + +节点 `B` 被加入最小优先队列,以便稍后遍历。 + +![Dijkstra step 2](./images/dijkstra-02.png) + +接着访问节点 `A` 的另一个邻居 `C`。 +从起始节点 `A` 到 `C` 的距离为 `0m + 9m = 9m`。 + +节点 `C` 被加入最小优先队列,等待后续遍历。 + +![Dijkstra step 3](./images/dijkstra-03.png) + +同样地,对于节点 `F`,从起始节点 `A` 的当前距离是 `0m + 14m = 14m`。 + +节点 `F` 被加入最小优先队列,等待后续遍历。 + +![Dijkstra step 4](./images/dijkstra-04.png) + +当当前节点的所有邻居都被检查完后,将当前节点添加到 `visited` 集合中。 +在后续遍历中不会再次访问这些节点。 + +现在,从优先队列中取出离起点最近(距离最短)的节点,开始访问它的邻居。 + +![Dijkstra step 5](./images/dijkstra-05.png) + +如果正在访问的节点(此处为 `C`)已经在队列中, +表示之前通过另一条路径(`A → C`)已计算过其距离。 +如果当前路径(`A → B → C`)的距离更短,则更新距离; +否则保持原状。 + +例如,通过 `B` 访问 `C`(路径 `A → B → C`),距离为 `7m + 10m = 17m`。 +这比已记录的 `A → C` 路径的 `9m` 更长,因此忽略。 + +![Dijkstra step 6](./images/dijkstra-06.png) + +访问 `B` 的另一个邻居 `D`。 +到 `D` 的距离为 `7m + 15m = 22m`。 +由于 `D` 尚未访问,也不在队列中,因此将其以距离 `22m` 的优先级加入队列。 + +![Dijkstra step 7](./images/dijkstra-07.png) + +此时,`B` 的所有邻居都已遍历,因此将 `B` 添加到 `visited` 集合中。 +接着,从优先队列中取出离起始节点最近的节点。 + +![Dijkstra step 8](./images/dijkstra-08.png) + +遍历节点 `C` 的未访问邻居。 +通过 `C` 到 `F` 的路径(`A → C → F`)距离为 `9m + 2m = 11m`。 +这比之前记录的路径 `A → F`(`14m`)更短。 +因此,将 `F` 的距离更新为 `11m`,并在队列中调整其优先级。 +我们找到了到 `F` 的更短路径。 + +![Dijkstra step 9](./images/dijkstra-09.png) + +对于 `D` 也是如此。 +路径 `A → C → D` 比 `A → B → D` 更短, +因此将距离从 `22m` 更新为 `20m`。 + +![Dijkstra step 10](./images/dijkstra-10.png) + +`C` 的所有邻居都已遍历完,将其加入 `visited`。 +然后从队列中取出下一个最近的节点 `F`。 + +![Dijkstra step 11](./images/dijkstra-11.png) + +记录到 `E` 的距离:`11m + 9m = 20m`。 + +![Dijkstra step 12](./images/dijkstra-12.png) + +将节点 `F` 添加到 `visited` 集合中,并从队列中取出下一个最近的节点 `D`。 + +![Dijkstra step 13](./images/dijkstra-13.png) + +通过 `D` 到 `E` 的距离为 `20m + 6m = 26m`。 +这比通过 `F` 的 `20m` 更长,因此忽略。 + +![Dijkstra step 14](./images/dijkstra-14.png) + +节点 `D` 已访问。 + +![Dijkstra step 15](./images/dijkstra-15.png) + +节点 `E` 也已访问。 +图的遍历完成。 + +![Dijkstra step 16](./images/dijkstra-16.png) + +现在,我们已经知道从起始节点 `A` 到每个节点的最短距离。 + +在实际应用中,在计算距离的同时,还会记录每个节点的 `previousVertices`(前驱节点), +以便重建形成最短路径的节点序列。 + +例如,从 `A` 到 `E` 的最短路径为 `A → C → F → E`。 + +## 实现示例 + +- [dijkstra.js](./dijkstra.js) + +## 参考资料 + +- [维基百科](https://zh.wikipedia.org/wiki/Dijkstra算法) +- [YouTube - Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) +- [YouTube - Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) diff --git a/src/algorithms/graph/dijkstra/README.zh-TW.md b/src/algorithms/graph/dijkstra/README.zh-TW.md new file mode 100644 index 0000000000..e960b41797 --- /dev/null +++ b/src/algorithms/graph/dijkstra/README.zh-TW.md @@ -0,0 +1,161 @@ +# Dijkstra 演算法 + +_以其他語言閱讀:_ +[_English_](README.md), +[_한국어_](README.ko-KR.md), +[_日本語_](README.ja-JP.md), +[_简体中文_](README.zh-CN.md), +[_繁體中文_](README.zh-TW.md), +[_Українська_](README.uk-UA.md), +[_Español_](README.es-ES.md), +[_Français_](README.fr-FR.md), +[_Deutsch_](README.de-DE.md), +[_עברית_](README.he-IL.md) + +Dijkstra 演算法是一種用於在圖中尋找節點之間最短路徑的演算法,例如,它可用於表示道路網絡。 + +該演算法有許多變體;Dijkstra 的原始版本用於尋找兩個節點之間的最短路徑,但更常見的變體是將一個節點固定為「起點(source)」節點,並從該節點計算到圖中所有其他節點的最短路徑,從而生成最短路徑樹(shortest-path tree)。 + +![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif) + +Dijkstra 演算法用於尋找從 `a` 到 `b` 的最短路徑。 +它會選擇距離最短且尚未訪問的節點,計算經由該節點到各個未訪問鄰居的距離, +若該距離更短,則更新鄰居的距離。 +當所有鄰居處理完畢後,將該節點標記為已訪問(紅色)。 + +## Dijkstra 演算法的實際應用 + +- GPS / 導航系統 +- 公共交通與航空路線最佳化 +- 網際網路路由(OSPF、IS-IS 協定) +- 網路流量與延遲最佳化 +- 電玩遊戲中的路徑尋找(地圖上的最短路徑) +- 物流與配送路線最佳化 +- 供應鏈與交通網路設計 + +## Dijkstra 演算法逐步範例 + +假設我們有一個帶權重的圖,每條邊都代表節點之間的距離。 +例如,節點 `A` 與節點 `B` 之間的距離為 `7 公尺`(簡稱 `7m`)。 + +演算法使用 [優先佇列(Priority Queue)](../../../data-structures/priority-queue/) +來不斷取出距離起點最近的未訪問節點。 + +起始節點與自身的距離定義為 `0m`,因此我們從它開始, +此時它是優先佇列中唯一的節點。 + +其餘節點會在圖遍歷過程中(訪問鄰居時)逐漸加入佇列。 + +![Dijkstra step 1](./images/dijkstra-01.png) + +從佇列中取出的節點,其每個鄰居都會被檢查,以計算從起點到該鄰居的距離。 +例如,從 `A` 到 `B` 的距離為 `0m + 7m = 7m`。 + +每當訪問尚未看過的鄰居時,就將其加入優先佇列, +其優先權為從起點到該鄰居的距離。 + +節點 `B` 被加入最小優先佇列,以便稍後處理。 + +![Dijkstra step 2](./images/dijkstra-02.png) + +接著訪問節點 `A` 的另一個鄰居 `C`。 +從起點 `A` 到 `C` 的距離為 `0m + 9m = 9m`。 + +節點 `C` 被加入最小優先佇列,等待後續遍歷。 + +![Dijkstra step 3](./images/dijkstra-03.png) + +同樣地,對於節點 `F`, +從起點 `A` 到 `F` 的距離為 `0m + 14m = 14m`。 + +節點 `F` 被加入最小優先佇列,以便稍後處理。 + +![Dijkstra step 4](./images/dijkstra-04.png) + +當目前節點的所有鄰居都被檢查完後, +將該節點加入 `visited` 集合中。 +之後將不再重新訪問該節點。 + +接著從佇列中取出距離起點最近的節點,開始訪問它的鄰居。 + +![Dijkstra step 5](./images/dijkstra-05.png) + +若正在訪問的節點(例如 `C`)已存在於佇列中, +代表先前已經透過另一條路徑(`A → C`)計算過其距離。 +若目前路徑(`A → B → C`)的距離更短,則更新距離; +若更長,則保持不變。 + +例如,透過 `B` 訪問 `C`(路徑 `A → B → C`)的距離為 `7m + 10m = 17m`, +比原先記錄的 `9m` 更長,因此不需更新。 + +![Dijkstra step 6](./images/dijkstra-06.png) + +接著訪問 `B` 的另一個鄰居 `D`。 +到 `D` 的距離為 `7m + 15m = 22m`。 +由於 `D` 尚未訪問,也不在佇列中,因此將其以優先權(距離)`22m` 加入佇列。 + +![Dijkstra step 7](./images/dijkstra-07.png) + +此時 `B` 的所有鄰居都已遍歷完, +因此將 `B` 加入 `visited` 集合中。 +接著從佇列中取出距離起點最近的節點。 + +![Dijkstra step 8](./images/dijkstra-08.png) + +訪問節點 `C` 的未訪問鄰居。 +經由 `C` 到 `F`(路徑 `A → C → F`)的距離為 `9m + 2m = 11m`。 +這比原本的路徑 `A → F`(`14m`)更短。 +因此,將 `F` 的距離更新為 `11m`,並調整其在佇列中的優先權。 +我們找到了更短的路徑。 + +![Dijkstra step 9](./images/dijkstra-09.png) + +對於 `D` 也是如此。 +經由 `C` 的路徑 `A → C → D` 比 `A → B → D` 更短, +因此將距離從 `22m` 更新為 `20m`。 + +![Dijkstra step 10](./images/dijkstra-10.png) + +`C` 的所有鄰居已被訪問,因此將 `C` 加入 `visited` 集合。 +接著從佇列中取出下一個最近的節點 `F`。 + +![Dijkstra step 11](./images/dijkstra-11.png) + +記錄到 `E` 的距離為 `11m + 9m = 20m`。 + +![Dijkstra step 12](./images/dijkstra-12.png) + +將節點 `F` 加入 `visited`,接著取出下一個最近的節點 `D`。 + +![Dijkstra step 13](./images/dijkstra-13.png) + +經由 `D` 到 `E` 的距離為 `20m + 6m = 26m`, +比透過 `F` 的 `20m` 更長,因此忽略。 + +![Dijkstra step 14](./images/dijkstra-14.png) + +節點 `D` 已訪問。 + +![Dijkstra step 15](./images/dijkstra-15.png) + +節點 `E` 也已訪問。 +圖的遍歷完成。 + +![Dijkstra step 16](./images/dijkstra-16.png) + +現在我們已經知道從起始節點 `A` 到各個節點的最短距離。 + +在實際應用中,計算距離的同時也會記錄每個節點的 `previousVertices`(前一節點), +以便重建出最短路徑的完整節點序列。 + +例如,從 `A` 到 `E` 的最短路徑為:`A → C → F → E`。 + +## 實作範例 + +- [dijkstra.js](./dijkstra.js) + +## 參考資料 + +- [維基百科](https://zh.wikipedia.org/wiki/Dijkstra算法) +- [YouTube - Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) +- [YouTube - Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)