AccueilđŸ‡«đŸ‡·Chercher

Algorithme de Dijkstra

En thĂ©orie des graphes, l'algorithme de Dijkstra (prononcĂ© [dɛÉȘkstra]) sert Ă  rĂ©soudre le problĂšme du plus court chemin. Il permet, par exemple, de dĂ©terminer un plus court chemin pour se rendre d'une ville Ă  une autre connaissant le rĂ©seau routier d'une rĂ©gion. Plus prĂ©cisĂ©ment, il calcule des plus courts chemins Ă  partir d'une source vers tous les autres sommets dans un graphe orientĂ© pondĂ©rĂ© par des rĂ©els positifs. On peut aussi l'utiliser pour calculer un plus court chemin entre un sommet de dĂ©part et un sommet d'arrivĂ©e.

Algorithme de Dijkstra
L'algorithme de Dijkstra pour trouver le chemin le plus court entre a et b. Il choisit le sommet non visité avec la distance la plus faible, calcule la distance à travers lui à chaque voisin non visité, et met à jour la distance du voisin si elle est plus petite. Il marque le sommet visité (en rouge) lorsque il a terminé avec les voisins.
DĂ©couvreur ou inventeur
Date de découverte
ProblÚmes liés
Algorithme de recherche de chemin (d), algorithme de la théorie des graphes (d), algorithme glouton, algorithme
Structure des données
Basé sur
À l'origine de
Algorithme A*, link-state routing protocol (en), Open Shortest Path First, IS-IS
Complexité en temps
Pire cas

Pour un graphe Ă  sommets et arcs :

pour l'implémentation avec un tas binaire,

pour l'implémentation avec un tas de Fibonacci

L'algorithme porte le nom de son inventeur, l'informaticien néerlandais Edsger Dijkstra, et a été publié en 1959[2].

Cet algorithme est de complexitĂ© polynomiale. Plus prĂ©cisĂ©ment, pour sommets et  arcs, le temps est en , voire en .

ProblĂšme du plus court chemin

L'algorithme de Dijkstra permet de rĂ©soudre un problĂšme algorithmique : le problĂšme du plus court chemin. Ce problĂšme a plusieurs variantes. La plus simple est la suivante : Ă©tant donnĂ© un graphe non-orientĂ©, dont les arĂȘtes sont munies de poids, et deux sommets de ce graphe, trouver un chemin entre les deux sommets dans le graphe, de poids minimum. L'algorithme de Dijkstra permet de rĂ©soudre un problĂšme plus gĂ©nĂ©ral : le graphe peut ĂȘtre orientĂ©, et l'on peut dĂ©signer un unique sommet, et demander d'avoir la liste des plus courts chemins pour tous les autres nƓuds du graphe.

Principe sur un exemple

L'algorithme prend en entrée un graphe orienté pondéré par des réels positifs et un sommet source. Il s'agit de construire progressivement un sous-graphe dans lequel sont classés les différents sommets par ordre croissant de leur distance minimale au sommet de départ. La distance correspond à la somme des poids des arcs empruntés.

Au départ, on considÚre que les distances de chaque sommet au sommet de départ sont infinies, sauf pour le sommet de départ pour lequel la distance est nulle. Le sous-graphe de départ est l'ensemble vide.

Au cours de chaque itération, on choisit en dehors du sous-graphe un sommet de distance minimale et on l'ajoute au sous-graphe. Ensuite, on met à jour les distances des sommets voisins de celui ajouté. La mise à jour s'opÚre comme suit : la nouvelle distance du sommet voisin est le minimum entre la distance existante et celle obtenue en ajoutant le poids de l'arc entre sommet voisin et sommet ajouté à la distance du sommet ajouté.

On continue ainsi jusqu'à épuisement des sommets (ou jusqu'à sélection du sommet d'arrivée).

Distance entre la ville A et la ville J

Animation d'un algorithme de Dijkstra
Étape 1 : on choisit la ville A. On met à jour les villes voisines de A qui sont B, C, et E. Leurs distances deviennent respectivement 85, 217, 173, tandis que les autres villes restent à une distance infinie.
Étape 2 : on choisit la ville B. En effet, c'est la ville hors du sous-graphe qui est à la distance minimale (85). On met à jour le seul voisin (F). Sa distance devient 85+80 = 165.
Étape 3 : on choisit F. On met à jour le voisin I (415).
Étape 4 : on choisit E. On met à jour le voisin J (675).
Étape 5 : la distance la plus courte en dehors du sous-graphe est maintenant celle de la ville C. On choisit donc C. On met à jour la ville G (403) et la ville H (320).
Étape 6 : la distance la plus courte en dehors du sous-graphe est maintenant celle de la ville H (320). On choisit donc H. On met à jour la ville D (503) et la ville J (487< 675).
Étape 7 : la distance la plus courte suivante est celle de la ville G. On choisit G. La mise à jour ne change aucune autre distance.
Étape 8 : la distance la plus courte suivante est celle de la ville I. La distance de la ville voisine J n'est pas modifiĂ©e car la distance existante est infĂ©rieure Ă  celle que l'on obtiendrait en passant par I (415 + 84 > 487).
Étape 9 : la ville dont la distance est la plus courte est J (487). On choisit J et on l'ajoute au sous-graphe. On s'arrĂȘte puisque la ville d'arrivĂ©e est maintenant dans le sous-graphe.
Play Pause Stop Précédent Suivant Select

L'algorithme de Dijkstra fonctionne aussi sur un graphe non orientĂ©. L'exemple ci-contre montre les Ă©tapes successives dans la rĂ©solution du chemin le plus court dans un graphe. Les nƓuds symbolisent des villes identifiĂ©es par une lettre et les arĂȘtes indiquent la distance entre ces villes. On cherche Ă  dĂ©terminer le plus court trajet pour aller de la ville A Ă  la ville J.

En neuf Ă©tapes, on peut dĂ©terminer le chemin le plus court menant de A Ă  J, il passe par C et H et mesure 487 km.

Présentation sous forme de tableau

On peut aussi résumer l'exécution de l'algorithme de Dijkstra avec un tableau. Chaque étape correspond à une ligne. Une ligne donne les distances courantes des sommets depuis le sommet de départ. Une colonne donne l'évolution des distances d'un sommet donné depuis le sommet de départ au cours de l'algorithme. La distance d'un sommet choisi (car minimale) est soulignée. Les distances mises à jour sont barrées si elles sont supérieures à des distances déjà calculées.

Algorithme de Dijkstra
Ă  A Ă  B Ă  C Ă  D Ă  E Ă  F Ă  G Ă  H Ă  I Ă  J
Ă©tape initiale 0 ∞ ∞ ∞ ∞ ∞ ∞ ∞ ∞ ∞
A(0) 85 217 ∞ 173 ∞ ∞ ∞ ∞ ∞
B(85A) - 217 ∞ 173 165 ∞ ∞ ∞ ∞
F(165B) - 217 ∞ 173 - ∞ ∞ 415 ∞
E(173A) - 217 ∞ - - ∞ ∞ 415 675
C(217A) - - ∞ - - 403 320 415 675
H(320C) - - 503 - - 403 - 415 675 487
G(403C) - - 503 - - - - 415 487
I(415F) - - 503 - - - - - 487
J(487H) - - 503 - - - - - -
D(503H) - - - - - - - - -

Le tableau donne non seulement la distance minimale de la ville A à la ville J (487) mais aussi le chemin à suivre à rebours (J - H - C - A) pour aller de A à J ainsi que toutes les distances minimales de la ville A aux autres villes rangées par ordre croissant.

Schéma de l'algorithme

Le graphe est notĂ© oĂč :

  • l'ensemble est l'ensemble fini des sommets du graphe ;
  • l'ensemble est l'ensemble des arcs de tel que : si est dans , alors il existe un arc depuis le nƓud vers le nƓud ;
  • on dĂ©finit la fonction dĂ©finie sur dans qui Ă  un couple associe le poids positif de l'arc reliant Ă  (et s'il n'y a pas d'arc reliant Ă  ).

Le poids du chemin entre deux sommets est la somme des poids des arcs qui le composent. Pour une paire donnée de sommets (le sommet du départ) (le sommet d'arrivée) appartenant à , l'algorithme trouve un chemin depuis vers de moindre poids (autrement dit un chemin le plus léger ou encore le plus court).

L'algorithme fonctionne en construisant un sous-graphe de maniĂšre Ă  ce que la distance entre un sommet de depuis soit connue et soit un minimum dans . Initialement, contient simplement le nƓud isolĂ©, et la distance de Ă  lui-mĂȘme vaut zĂ©ro. Des arcs sont ajoutĂ©s Ă  Ă  chaque Ă©tape :

1. en identifiant tous les arcs dans ;
2. en choisissant l'arc dans qui donne la distance minimum depuis Ă  en passant tous les chemins crĂ©Ă©s menant Ă  ce nƓud.

L'algorithme se termine soit quand devient un arbre couvrant de , soit quand tous les nƓuds d'intĂ©rĂȘt[3] sont dans .

On peut donc écrire l'algorithme de la façon suivante :

Entrées :  un graphe avec une pondération positive  des arcs,  un sommet de 

 pour chaque sommet 

Tant qu'il existe un sommet hors de 
    Choisir un sommet  hors de  de plus petite distance 
    Mettre  dans  
    Pour chaque sommet  hors de   voisin de 
       Si d[b] > d[a] + poids(a, b)
           
           prédécesseur[b] := a
    Fin Pour
Fin Tant Que

Implémentation de l'algorithme

Fonctions annexes

L'algorithme utilise les fonctions annexes suivantes.

Initialisation de l'algorithme

Initialisation(G,sdeb)
1 pour chaque point s de G faire
2    d[s] := infini             /* on initialise les sommets autres que sdeb Ă  infini */[4]
3 fin pour
4 d[sdeb] := 0                  /* la distance au sommet de départ sdeb est nulle */

Recherche d'un nƓud de distance minimale

  • On recherche un nƓud de distance minimale (reliĂ© par l'arc de poids le plus faible) de parmi les nƓuds situĂ©s hors de . Le complĂ©mentaire de est notĂ© . On implĂ©mente pour cela une fonction Trouve_min(Q) qui choisit un nƓud de Q de distance minimale.
Trouve_min(Q)
1 mini := infini
2 sommet := -1
3 pour chaque sommet s de Q
4    si d[s] < mini
5    alors 
6        mini := d[s]
7        sommet := s
8 renvoyer sommet

Mise Ă  jour des distances

  • On met Ă  jour les distances entre et en se posant la question : vaut-il mieux passer par ou pas ?
maj_distances(s1,s2)
1 si d[s2] > d[s1] + Poids(s1,s2)      /* Si la distance de sdeb Ă  s2 est plus grande que */
2                                      /* celle de sdeb Ă  S1 plus celle de S1 Ă  S2 */
3    alors 
4        d[s2] := d[s1] + Poids(s1,s2) /* On prend ce nouveau chemin qui est plus court */
5        prĂ©dĂ©cesseur[s2] := s1        /* En notant par oĂč on passe */

Fonction principale

Voici la fonction principale utilisant les précédentes fonctions annexes :

Dijkstra(G,Poids,sdeb)
1 Initialisation(G,sdeb)
2 Q := ensemble de tous les nƓuds
3 tant que Q n'est pas un ensemble vide faire
4       s1 := Trouve_min(Q)
5       Q := Q privé de s1
6       pour chaque nƓud s2 voisin de s1 faire
7           maj_distances(s1,s2)
8       fin pour
9 fin tant que

Le plus court chemin de à peut ensuite se calculer itérativement selon l'algorithme suivant, avec la liste représentant le plus court chemin de à :

1 A := suite vide
2 s := sfin
3 tant que s != sdeb faire
4   A := cons(s, A)            /* on ajoute s en tĂȘte de la liste A */
5   s := prédécesseur[s]       /* on continue de suivre le chemin */
6 fin tant que
7 A := cons(sdeb, A)           /* on ajoute le nƓud de dĂ©part */

Attention : s'il n'y a pas de chemin de à cette partie de l'algorithme fait une boucle infinie ou une erreur selon votre implémentation.

Spécialisation de l'algorithme

Il est possible de spĂ©cialiser l'algorithme en arrĂȘtant la recherche lorsque l'Ă©galitĂ© est vĂ©rifiĂ©e, dans le cas oĂč on ne cherche que la distance minimale entre et .

Complexité de l'algorithme

L'efficacitĂ© de l'algorithme de Dijkstra repose sur une mise en Ɠuvre efficace de Trouve_min. L'ensemble est implĂ©mentĂ© par une file Ă  prioritĂ©s. Si le graphe possĂšde arcs et nƓuds, qu'il est reprĂ©sentĂ© par des listes d'adjacence et si on implĂ©mente la file Ă  prioritĂ©s par un tas binaire (en supposant que les comparaisons des poids d'arcs soient en temps constant), alors la complexitĂ© en temps de l'algorithme est . En revanche, si on implĂ©mente la file Ă  prioritĂ©s avec un tas de Fibonacci, l'algorithme est en [5].

Correction de l'algorithme

La démonstration de correction est une récurrence sur Card(P) (qui augmente de 1 à chaque itération) et repose sur l'invariant suivant :

oĂč :

  • mini(c) est le poids d'un plus court chemin menant Ă  c ;
  • miniP(c) est le poids d'un plus court chemin dont tous les sommets intermĂ©diaires sont dans P menant Ă  c.

Si n = Card(P), la preuve est la suivante :

  • pour n = 0 et 1 : immĂ©diat ;
  • pour n un entier non nul, supposons l'invariant vrai.

L'algorithme sélectionne un pivot tel que , et l'ajoute dans P. Il faut donc montrer que aprÚs modification de P:

Par hypothĂšse, avant modification de P, donc s'il existe un chemin C tel que alors ce chemin contient au moins un sommet b a tel que .

Soit donc un tel sommet b tel que tous ses prĂ©dĂ©cesseurs dans C soient dans P (il existe car le premier sommet de C est l'origine qui est dans P). DĂ©composons C en Cb- et Cb+ oĂč Cb- est la premiĂšre partie de C dont le dernier sommet est b, et Cb+ la suite de C. Alors : contradiction.

Il n'existe donc aucun chemin C tel que d'oĂč . L'Ă©galitĂ© est toujours vraie pour les autres Ă©lĂ©ments de P.

Enfin, l'algorithme met à jour la fonction d (et prédécesseur) pour les successeurs b du pivot a : .

Montrons qu'alors, :

  • si c n'est pas un successeur du pivot a, alors il n'existe aucun nouveau chemin C menant Ă  c tel que et dont tous les sommets intermĂ©diaires sont dans P aprĂšs l'ajout de a dans P puisqu'il faudrait alors passer par a avant de passer par un autre sommet , mais ce ne serait pas le plus court chemin jusqu'Ă  d puisque le poids du plus court chemin jusqu'Ă  d a dĂ©jĂ  Ă©tĂ© calculĂ© avant l'ajout de a dans P par hypothĂšse, et ce chemin ne contient donc que des sommets ayant Ă©tĂ© dans P avant l'ajout de a dans P ;
  • sinon, il existe de tels chemins, en notant C le meilleur d'entre eux, alors C sera un des nouveaux chemins engendrĂ©s par l'ingestion du pivot a par P, donc et d'autre part le pivot a est le dernier sommet intermĂ©diaire de C puisque le plus court chemin menant aux autres sommets de P ne passe par a comme expliquĂ© plus haut. C est donc la rĂ©union du plus court chemin menant Ă  a avec l'arc (a, c) : d'oĂč .

Applications

L'algorithme de Dijkstra trouve une utilitĂ© dans le calcul des itinĂ©raires routiers. Le poids des arcs pouvant ĂȘtre la distance (pour le trajet le plus court), le temps estimĂ© (pour le trajet le plus rapide), la consommation de carburant et le prix des pĂ©ages (pour le trajet le plus Ă©conomique).

Une application courante de l'algorithme de Dijkstra apparaĂźt dans les protocoles de routage interne « Ă  Ă©tat de liens », tels que Open Shortest Path First (OSPF)[6] ou IS-IS[7] – ou encore PNNI (en) sur les rĂ©seaux ATM –, qui permettent un routage internet trĂšs efficace des informations en cherchant le parcours le plus efficace.

Comparaison avec d'autres algorithmes

  • L'algorithme de Dijkstra est fondĂ© sur un parcours en largeur.
  • La spĂ©cialisation de l'algorithme de Dijkstra qui calcule un plus court chemin d'une source Ă  une destination est une instance de l'algorithme A* dans lequel la fonction heuristique est la fonction nulle. L'algorithme A* qui utiliserait une heuristique minorante et monotone (par exemple la distance Ă  vol d'oiseau) peut ĂȘtre plus efficace .
  • L'algorithme ne s'applique pas aux graphes avec des poids nĂ©gatifs. Mais l'algorithme de Bellman-Ford permet de rĂ©soudre le problĂšme des plus courts chemins depuis une source avec des poids nĂ©gatifs (mais sans cycle nĂ©gatif).
  • L'algorithme de Floyd-Warshall calcule des plus courts chemins entre tous les sommets dans un graphe oĂč les poids peuvent ĂȘtre nĂ©gatifs.

Notes et références

  1. (en) E. W. Dijkstra, « A note on two problems in connexion with graphs », Numerische Mathematik, Springer Science+Business Media, vol. 1, no 1,‎ , p. 269-271 (ISSN 0029-599X et 0945-3245, OCLC 1760917, DOI 10.1007/BF01386390, lire en ligne)
  2. Dijkstra, E. W., « A note on two problems in connexion with graphs », Numerische Mathematik, vol. 1,‎ , p. 269–271 (DOI 10.1007/BF01386390.).
  3. Par exemple, les nƓuds n'ayant pas d'arĂȘtes autres que celle que l'on a parcourue pour arriver Ă  eux, ne sont pas considĂ©rĂ©s comme des nƓuds d'intĂ©rĂȘt.
  4. La suite de caractĂšres /* ... */ est un commentaire.
  5. Cormen et al. 2010, p. 610
  6. (en) John Moy, « RFC2328 OSPF Version 2 », (consultĂ© le ) : « Using the Dijkstra algorithm, a tree is formed from this subset of the link state database. », p. 161
  7. (en) David R. Oran, « RFC1142 : OSI IS-IS Intra-domain Routing Protocol », (consultĂ© le ) : « An algorithm invented by Dijkstra (see references) known as shortest path first (SPF), is used as the basis for the route calculation. »

Annexes

Bibliographie

Articles connexes

Liens externes

Cet article est issu de wikipedia. Text licence: CC BY-SA 4.0, Des conditions supplĂ©mentaires peuvent s’appliquer aux fichiers multimĂ©dias.