L'algorithme de Dijsktra : C++, Python Exemple de code

Quel est le chemin le plus court ou la distance la plus courte ?

Un chemin allant du sommet source au sommet de destination qui coรปte un minimum est le chemin le plus court ou la distance la plus courte. En thรฉorie des graphes, il est possible dโ€™avoir plusieurs itinรฉraires depuis une source vers une destination. Entre ces itinรฉraires, sโ€™il existe un itinรฉraire qui coรปte un montant minimum, nous pouvons lโ€™appeler lโ€™algorithme du chemin le plus court.

Ici, ยซ Coรปt ยป dรฉsigne le nombre de nล“uds dans l'itinรฉraire ou la somme des coรปts sur chaque chemin. Un chemin peut avoir un ou plusieurs bords. La connexion entre deux sommets est appelรฉe ยซ arรชte ยป. Il existe diffรฉrents types d'algorithmes de chemin le plus court, comme l'algorithme de Dijkstra, l'algorithme de Bellman-Ford, etc.

Ici, nous discutons de l'algorithme de Dijkstra

Regardons le graphique pondรฉrรฉ suivant :

Un graphique non pondรฉrรฉ
Un graphique non pondรฉrรฉ
  • Le terme ยซ pondรฉrรฉ ยป signifie dรฉplacer les coรปts dโ€™un nล“ud ร  un autre. Par exemple, en passant du nล“ud 1 au nล“ud 2, le coรปt ou le poids est de 1.
  • Le chemin entre le nล“ud 1 et le nล“ud 2 est appelรฉ le bord.
  • ยซ Non dirigรฉ ยป signifie que vous pouvez dรฉplacer un nล“ud vers un autre et revenir au nล“ud prรฉcรฉdent. Donc, si nous essayons de trouver toutes les routes du nล“ud 1 au nล“ud 7, alors ce sera :
Itinรฉraire ou chemin Prix
1 2 6-7 (1+3+3) = 7
1 2 3-7 (1+9+1) = 11
1-3-7 (7+1) = 8
1 4 5-7 (6+2+5) = 13

Parmi ces quatre itinรฉraires, nous pouvons voir que le premier itinรฉraire nous coรปtera 7. C'est donc le chemin le plus court en termes de coรปt.

Le plus court chemin

Le plus court chemin

Comment fonctionne l'algorithme de Dijkstra

L'algorithme de Dijkstra peut trouver la distance la plus courte dans les graphiques pondรฉrรฉs orientรฉs et non orientรฉs. Cet algorithme est gourmand car il choisit toujours le nล“ud le plus court ou le plus proche de l'origine. Le terme ยซ gourmand ยป signifie que parmi un ensemble dโ€™issues ou de rรฉsultats, lโ€™algorithme choisira le meilleur dโ€™entre eux.

Ici, nous essayons de trouver les chemins les plus courts parmi tous les autres itinรฉraires. Ainsi, l'algorithme de Dijkstra trouve tous les chemins les plus courts ร  partir d'un seul nล“ud de destination. De ce fait, il se comporte comme un algorithme gourmand.

Dans la section ยซ exemple ยป ci-dessous, vous verrez l'approche รฉtape par รฉtape. Cela fonctionne comme suit :

ร‰tape 1) Initialisez le nล“ud de dรฉpart avec 0 coรปt et le reste du nล“ud avec Infinity Cost.
ร‰tape 2) Maintenir un tableau ou une liste pour garder une trace des nล“uds visitรฉs
ร‰tape 3) Mettez ร  jour le coรปt du nล“ud avec le coรปt minimum. Cela peut รชtre fait en comparant le coรปt actuel avec le coรปt du chemin. (La dรฉmonstration est prรฉsentรฉe dans la section exemple)
ร‰tape 4) Continuez l'รฉtape 3 jusqu'ร  ce que tous les nล“uds soient visitรฉs.

Aprรจs avoir complรฉtรฉ toutes ces รฉtapes, nous trouverons le chemin qui coรปte le moins cher de la source ร  la destination.

Diffรฉrence entre Dijkstra et BFS, DFS

La principale diffรฉrence entre Dijkstra et BFS-DFS est que Dijkstra est l'algorithme de recherche de chemin le plus court et que BFS, DFS est l'algorithme de recherche de chemin. Dans les cas gรฉnรฉraux, BFS et DFS ne prennent pas en compte le coรปt lors de la recherche du chemin. Ces algorithmes ne peuvent donc pas garantir le chemin le plus court.

Dรฉmonstration de grille 2D du fonctionnement de BFS

Dรฉmonstration de grille 2D

Algosketch, montrant la dรฉmonstration BFS

Cette dรฉmonstration indique que BFS trouve uniquement le chemin. Toutefois, il ne se soucie pas du poids du chemin. BFS (Recherche en largeur d'abord) suppose que voyager dโ€™un nล“ud ร  un autre ne coรปtera que 1.

Mais voyons un exemple de graphique :

Dรฉmonstration de grille 2D

Ici, il trouve un chemin au niveau 2. BFS parcourt le graphique dans l'ordre des niveaux. Donc รงa voyage comme :

ร‰tape 1) Commencez par le nล“ud ยซ 1 ยป et visitez tous les nล“uds adjacents 2,3,4

ร‰tape 2) Marquez les nล“uds 2,3,4 comme niveau 1 et visitez leurs nล“uds adjacents. Il continuera ร  explorer tous les nล“uds adjacents jusqu'ร  ce qu'il atteigne le nล“ud de destination.

En termes de DFS, il parcourra le chemin de 1 ร  7 comme suit :

  • 1 โ†’ 2 โ†’ 3 โ†’ 7 (coรปt initial 10, coรปt DFS 3)
  • 1 โ†’ 2 โ†’ 6 โ†’ 7 (coรปt initial 7, coรปt DFS 3)
  • 1 โ†’ 3 โ†’ 7 (coรปt initial 8, coรปt DFS 2)
  • 1 โ†’ 4 โ†’ 5 โ†’ 7 (coรปt initial 13, coรปt DFS 3)

Comme nous le voyons, DFS calcule son coรปt de chemin avec le nombre de profondeur ou le nombre d'arรชtes.

DFS effectue les opรฉrations suivantes :

  • DFS peut trouver un chemin depuis la source (sommet de dรฉpart) jusqu'ร  la destination.
  • Il ne peut pas garantir si le chemin dรฉcouvert du nล“ud source ร  la destination est le chemin le plus court ou non.

Cependant, en termes dโ€™algorithme de Dijkstra, il choisira les arรชtes en fonction de leur coรปt. En tant qu'algorithme glouton, il sรฉlectionnera les chemins les meilleurs ou les moins coรปteux.

Exemple de l'algorithme de Dijkstra

L'algorithme de Dijkstra utilise le coรปt ou le poids pour calculer le coรปt total du chemin.

Exemple de l'algorithme de Dijkstra

L'objectif de l'algorithme de Dijkstra est de minimiser ce coรปt ou ce poids total. Dans l'exemple ci-dessus, nous trouvons les meilleurs chemins du nล“ud 1 au nล“ud 7, puis calculons tous les coรปts.

Dans l'algorithme de Dijkstra, il trouvera les chemins les plus courts en calculant des poids. Il ne cherchera pas tous les chemins possibles. Dรฉmontrons l'algorithme de Dijkstra avec un exemple. Par exemple, il vous a รฉtรฉ demandรฉ de trouver le chemin le plus court entre le nล“ud 1 et le nล“ud 7.

Pour ce processus, les รฉtapes sont indiquรฉes ci-dessous :

ร‰tape 1) Initialisez le coรปt du nล“ud de dรฉpart ร  0.

Reste du nล“ud, attribuer ยซ Inf ยป. Cela signifie qu'aucun chemin n'existe entre le sommet de dรฉpart (la source) et le nล“ud, ou que le chemin n'est pas encore visitรฉ.

Exemple de l'algorithme de Dijkstra

ร‰tape 2) Lorsque vous sรฉlectionnez le nล“ud 1, il sera marquรฉ comme visitรฉ. Mettez ensuite ร  jour tous les voisins adjacents du nล“ud 1. 2,3,4 sont les nล“uds voisins du nล“ud 1.

Lors de la mise ร  jour d'un coรปt, nous devons suivre la procรฉdure ci-dessous :

Exemple de l'algorithme de Dijkstra

Nous pouvons mettre ร  jour le coรปt de chaque nล“ud en utilisant la formule ci-dessus. Par exemple, nous รฉtions au nล“ud 1 et nous devions mettre ร  jour le coรปt de son nล“ud adjacent 2,3,4.

Aprรจs la mise ร  jour, le coรปt ou le poids ressemblera ร  ceci :

Exemple de l'algorithme de Dijkstra

ร‰tape 3) Pour le nล“ud ยซ 2 ยป, les voisins sont 6 et 3. Nous mettons ร  jour le coรปt ร  ยซ 6 ยป en comparant l'infini (valeur actuelle). Le coรปt du nล“ud 2 + le coรปt du chemin de 2 ร  6. En termes simples, le nล“ud ยซ 6 ยป aura le coรปt de 1+3 ou 4.

Exemple de l'algorithme de Dijkstra

Le nล“ud 3 est voisin du nล“ud 2. Cependant, nous avons calculรฉ son coรปt ร  l'รฉtape prรฉcรฉdente, qui รฉtait de 7. Maintenant, si notre chemin est 1-2-3, le nล“ud 3 aura un coรปt de 10. Chemin 1-2- 3 coรปtera 10, tandis que 1 ร  3 coรปtera 7.

ร‰tape 4) Pour le nล“ud 3, le nล“ud voisin est 7. Ainsi, en comparant la valeur actuelle du nล“ud 7 avec le coรปt du chemin (7+1) ou 8, nous mettrons ร  jour le coรปt du nล“ud 7. Soit 8.

Nous trouvons donc un chemin du nล“ud 1 au nล“ud 7, et il vaut 1 โ†’ 3 โ†’ 7. Le coรปt est de 8.

ร‰tape 5) Pour le nล“ud 4, nous mettrons ร  jour son coรปt de nล“ud adjacent en consรฉquence. Ainsi, le nล“ud ยซ 5 ยป aura un coรปt mis ร  jour de 8. Aprรจs l'รฉtape 4,5, il ressemblera ร  ceci :

Exemple de l'algorithme de Dijkstra

Dรฉsormais, le chemin 1-3-7 coรปte 8 (auparavant). Le nล“ud ยซ 7 ยป n'a pas รฉtรฉ marquรฉ comme visitรฉ car nous pouvons atteindre le nล“ud ยซ 7 ยป ร  partir du nล“ud ยซ 6 ยป. Le chemin ยซ 1-2-6 ยป avait un coรปt de 4. Le chemin 1-2-6-7 aura donc un coรปt de 7.

Comme 7 < 8, c'est pourquoi le chemin le plus court du sommet source ยซ 1 ยป au sommet de destination ยซ 7 ยป sera 1-2-6-7, et le coรปt est 7. Auparavant, c'รฉtait 1-3-7, et le coรปt avait 8 ans.

Ainsi, le graphique final ressemblera ร  ceci :

Exemple de l'algorithme de Dijkstra

Le bord marquรฉ d'une ligne noire est notre chemin le plus court de 1 ร  7, et il nous en coรปtera 7.

Algorithme du pseudo-code Dijkstra

Voici le pseudo-code de l'algorithme de Dijkstra

Dijkstra(G, S):  
  for each vertex V in G
    distance[V] & lt; - Infinity
    previous[V] & lt; - NULL
  if V does not equal S, then, 
    (priority queue) Q.push(V)
  distance[S] = 0
  While Q is not empty
   U & lt; - Extract the MIN from Q
   For each unvisited adjacent V of U
   TotalDistance & lt; - distance[U] + edge_cost(U, V)
   if TotalDistance is less than distance[V], then
     distance[V] & lt; - TotalDistance
     previous[V] & lt; - u
  return distance, previous

C++ implรฉmentation de l'algorithme de Dijkstra

Pour implรฉmenter l'algorithme de Dijkstra en utilisant C++, voici le code :

#include <bits/stdc++.h>
using namespace std;
#define size 7
int minimumDistance(int distance[], bool visited[]) {
  int min = INT_MAX;
  int min_index = INT_MAX;
  for (int i = 0; i < size; i++) {
    if (!visited[i] & amp; & distance[i] <= min) {
      min = distance[i];
      min_index = i;
    }
  }
  return min_index;
}
void printParentPath(int parent[], int i) {
  if (parent[i] == -1) {
    return;
  }
  printParentPath(parent, parent[i]);
  cout << i + 1 << " ";
}
void dijkstra(int graph[size][size], int source) {
  int distance[size];
  bool visited[size];
  int parent[size];
  for (int i = 0; i < size; i++) {
    parent[0] = -1;
    distance[i] = INT_MAX;
    visited[i] = false;
  }
  distance[source] = 0;
  for (int i = 0; i < size - 1; i++) {
    int U = minimumDistance(distance, visited);
    visited[U] = true;
    for (int j = 0; j < size; j++) {
      int curr_distance = distance[U] + graph[U][j];
      if (!visited[j] & amp; & graph[U][j] & amp; &
          curr_distance < distance[j]) {
        parent[j] = U;
        distance[j] = curr_distance;
      }
    }
  }
  cout << "Vertex\t\tDistance\tPath" << endl;
  for (int i = 1; i < size; i++) {
    cout << source + 1 << "->" << i + 1 << "\t\t" << distance[i] << "\t\t"
         << source + 1 << " ";
    printParentPath(parent, i);
    cout << endl;
  }
}
int main() {
  int graph[size][size] = {{0, 1, 7, 6, 0, 0, 0}, {1, 0, 9, 0, 0, 3, 0},
                           {7, 9, 0, 0, 0, 0, 1}, {6, 0, 0, 0, 2, 0, 0},
                           {0, 0, 0, 2, 0, 0, 0}, {0, 3, 0, 0, 0, 0, 3},
                           {0, 0, 0, 0, 5, 3, 0}};
  dijkstra(graph, 0);
}

Sortie :

Vertex     Distance        Path

1->2           1             1 2
1->3           7             1 3
1->4           6             1 4
1->5           8             1 4 5
1->6           4             1 2 6
1->7           7             1 2 6 7

Python implรฉmentation de l'algorithme de Dijkstra

Pour implรฉmenter l'algorithme de Dijkstra en utilisant python, voici le code :

num_of_vertex = 7
def minimumDistance(distance, visited): 
  _min = 1e11
  min_index = 1e11
for i in range(num_of_vertex): 
  if not visited[i] and distance[i] & lt; = _min: 
   _min = distance[i]
   min_index = i
return min_index
def printParentNode(parent, i): 
  if parent[i] == -1: 
   return
  printParentNode(parent, parent[i])
  print("{} ".format(i + 1), end = "")
def dijkstra(graph, src): 
  distance = list()
  visited = list()
  parent = list()
for i in range(num_of_vertex): 
  parent.append(-1)
  distance.append(1e11)
  visited.append(False)
distance[src] = 0
for i in range(num_of_vertex - 1): 
  U = minimumDistance(distance, visited)
  visited[U] = True
for j in range(num_of_vertex): 
  curr_distance = distance[U] + graph[U][j]
  if not visited[j] and graph[U][j] and curr_distance & lt;
    distance[j]: parent[j] = U
    distance[j] = curr_distance
  print("Vertex\t\tDistance\tPath")
for i in range(num_of_vertex): 
  print("{}->{}\t\t{}\t\t{} 
".format(src + 1, i + 1, distance[i], src + 1), end = "")
  printParentNode(parent, i)
print("")
graph = [
  [0, 1, 7, 6, 0, 0, 0],
  [1, 0, 9, 0, 0, 3, 0],
  [7, 9, 0, 0, 0, 0, 1],
  [6, 0, 0, 0, 2, 0, 0],
  [0, 0, 0, 2, 0, 0, 0],
  [0, 3, 0, 0, 0, 0, 3],
  [0, 0, 0, 0, 5, 3, 0]
]
dijkstra(graph, 0)

Sortie :

Vertex     Distance        Path

1->1           0              1
1->2           1              1 2
1->3           7              1 3
1->4           6              1 4
1->5           8              1 4 5
1->6           4              1 2 6
1->7           7              1 2 6 7

Nous pouvons voir que l'algorithme calcule la distance la plus courte depuis le nล“ud source.

Application de l'algorithme de Dijkstra

Le Dijkstra Algo a un large รฉventail dโ€™utilisations. Parmi ceux-ci, il est largement utilisรฉ dans le domaine des rรฉseaux. Voici quelques exemples d'utilisation rรฉelle de l'algorithme de Dijkstra :

Dijkstra sur la carte Google : Fondamentalement, cet algorithme est lโ€™รฉpine dorsale de la recherche des chemins les plus courts. Comme nous pouvons le voir dans la sortie de lโ€™extrait de code ci-dessus.

Application de l'algorithme de Dijkstra

Google n'utilise pas le simple algorithme de Dijkstra. Au lieu de cela, il utilise une version modifiรฉe. Lorsque vous sรฉlectionnez une destination, plusieurs chemins sont affichรฉs sur Google Map. Parmi ces chemins, certains chemins sont triรฉs pour l'utilisateur. Ces chemins sรฉlectionnรฉs sont basรฉs sur le ยซ temps ยป. Ainsi, le ยซ temps ยป est un coรปt supplรฉmentaire pour le chemin le plus court.

Dijkstra dans le routage IP : Routage IP est une terminologie de rรฉseautage. Cela signifie comment votre paquet de donnรฉes est envoyรฉ au rรฉcepteur via diffรฉrents chemins. Ces chemins sont constituรฉs de routeurs, de serveurs, etc. Dans le routage IP, il existe diffรฉrents types de protocoles.

Ces protocoles aident le routeur ร  trouver les chemins les plus courts pour envoyer les donnรฉes. L'un des noms de protocole est ยซ OSPF (Open Shortest Path First) ยป. OSPF utilise l'algorithme de Dijkstra. Le routeur gรจre une table de routes. Chaque routeur partage sa table avec les routeurs voisins. Aprรจs avoir reรงu le tableau mis ร  jour, ils doivent recalculer tous les chemins. ร€ ce moment-lร , le routeur utilise lโ€™algorithme Dijkstra.

Limitation de l'algorithme de Dijkstra

L'algorithme de Dijkstra ne peut pas garantir le chemin le plus court dans le graphe des bords nรฉgatifs. L'algorithme de Dijkstra suit ces mรฉthodologies :

  • Un chemin le plus court sera empruntรฉ dโ€™un nล“ud ร  un autre.
  • Une fois le chemin le plus court entre deux nล“uds sรฉlectionnรฉ, il ne sera plus calculรฉ.

Ici, remarquez deux exemples avec des bords nรฉgatifs.

Limitation de l'algorithme de Dijkstra

Dans le graphique de gauche, il y a trois sommets. Dijkstra fonctionnera sur le graphique comme suit :

ร‰tape 1) Le sommet de dรฉpart ยซ 1 ยป sera initialisรฉ ร  zรฉro. Les autres nล“uds auront l'infini.

Limitation de l'algorithme de Dijkstra

ร‰tape 2) Marquez le nล“ud ยซ 1 ยป comme visitรฉ et incluez-le dans le chemin le plus court.

ร‰tape 3) La distance du nล“ud source 1 aux nล“uds ยซ 2 ยป et ยซ 3 ยป est fixรฉe ร  l'infini, car le chemin le plus court reste ร  calculer. Ainsi, tout chemin qui coรปtera moins que lโ€™infini sera ajoutรฉ au chemin le plus court (approche gourmande).

ร‰tape 4) Mise ร  jour de la distance du sommet source ou du nล“ud source ยซ 1 ยป ร  ยซ 2 ยป. Le poids actuel sera de 5 (5

Limitation de l'algorithme de Dijkstra

ร‰tape 5) Maintenant, si nous vรฉrifions les distances les plus courtes depuis le nล“ud ยซ 1 ยป, nous constatons que 5 est la distance la plus courte pour le bord 1 -> 2. Ainsi, le nล“ud ยซ 2 ยป sera marquรฉ comme visitรฉ.

De mรชme, le nล“ud ยซ 3 ยป sera รฉgalement marquรฉ comme visitรฉ car la distance la plus courte est 3.

Cependant, si nous observons, il existe un chemin 1-3-2 qui ne coรปtera que 2. Mais le Dijkstra montre que du nล“ud ยซ 1 ยป au nล“ud ยซ 2 ยป, la distance la plus courte est 5. Ainsi, Dijkstra n'a pas rรฉussi ร  calculer la distance la plus courte. distance correctement. La raison pour laquelle cela s'est produit est que Dijkstra est un algorithme gourmand. Ainsi, une fois qu'un nล“ud est marquรฉ comme visitรฉ, il ne sera pas reconsidรฉrรฉ, mรชme s'il peut y avoir un chemin plus court disponible. Ce problรจme se produit uniquement lorsque les arรชtes ont des coรปts nรฉgatifs ou des arรชtes de poids nรฉgatifs.

Dijkstra ne parvient pas ร  calculer le chemin le plus court entre deux nล“uds dans ce scรฉnario. En consรฉquence, cet algorithme prรฉsente certains inconvรฉnients. Pour rรฉsoudre ce problรจme de bord nรฉgatif, un autre algorithme appelรฉ ยซ Algorithme Bellman-Ford ยป est utilisรฉ. Cet algorithme peut fonctionner avec des bords nรฉgatifs.

Complexitรฉ de l'algorithme de Dijkstra

L'implรฉmentation ci-dessus utilisait deux boucles ยซ for ยป. Ces boucles s'exรฉcutent pour le nombre de sommets. La complexitรฉ temporelle est donc O(V2). Ici, le terme ยซ 0 ยป dรฉsigne une notation qui donne une hypothรจse pour l'algorithme de Dijkstra.

Nous pouvons stocker le graphique en utilisant la ยซ file dโ€™attente prioritaire ยป. Une file d'attente prioritaire est une structure de donnรฉes de tas binaire. Ce sera plus efficace quโ€™une matrice 2D. Un avantage qui aura un coรปt minimum aura une haute prioritรฉ.

La complexitรฉ temporelle sera alors O (E log (V)). Ici, E est le nombre dโ€™arรชtes et V est le nombre de sommets.

La complexitรฉ de l'espace est O(V2), car nous utilisons une matrice de contiguรฏtรฉ (tableau 2D). La complexitรฉ de l'espace peut รชtre optimisรฉe ร  l'aide d'une liste de contiguรฏtรฉ ou d'une structure de donnรฉes de file d'attente.

Rรฉsumez cet article avec :