Plus Courts Chemins

L'Algorithme de Dijkstra expliqué, pas à pas

L'algorithme de Dijkstra est le cheval de bataille des plus courts chemins. Il fait tourner votre GPS, votre routage réseau et une grande part des entretiens de code. Ce guide le construit depuis l'idée centrale jusqu'à un exemple entièrement résolu et un code Python propre.

12 Min de lecture Mis à jour : Juillet 2026 Accessible aux débutants
Mohammed Islam Hadjoudj
Mohammed Islam Hadjoudj
Expert Operations Research Engineer

Qu'est-ce que l'Algorithme de Dijkstra ?

L'algorithme de Dijkstra, publié par Edsger W. Dijkstra en 1959, trouve le plus court chemin depuis une seule source vers tous les autres nœuds d'un graphe pondéré. Il fonctionne sur les graphes orientés comme non orientés, avec une condition ferme : chaque poids d'arête doit être non négatif.

Voyez le graphe comme un réseau routier. Les nœuds sont des carrefours, les arêtes des routes, et chaque poids est le temps ou la distance pour parcourir cette route. L'algorithme de Dijkstra répond à la question que pose toute application de navigation : quel est l'itinéraire le plus rapide d'où je suis vers partout ailleurs ? C'est un élément de la famille plus large traitée dans les algorithmes de plus courts chemins, et un incontournable de la feuille de route de la théorie des graphes.

L'Idée Centrale

L'algorithme de Dijkstra est glouton. Il conserve une distance la plus courte provisoire vers chaque nœud et répète un geste simple :

Visitez toujours le nœud non visité ayant la plus petite distance connue, puis servez-vous-en pour améliorer ses voisins.

L'intuition qui rend cela correct : comme tous les poids sont non négatifs, dès que vous choisissez le nœud non visité le plus proche, aucun chemin futur ne pourra l'atteindre à moindre coût. Ainsi, à l'instant où un nœud est choisi, sa distance est définitive. Cette seule garantie constitue tout l'algorithme.

Concrètement, l'algorithme entretient :

Améliorer un voisin s'appelle la relaxation : si le chemin passant par le nœud courant est plus court que la distance enregistrée du voisin, vous l'abaissez.

Comment ça Marche, Pas à Pas

Exécutons Dijkstra depuis le nœud A sur ce graphe pondéré. Les arêtes bleues formeront l'arbre final des plus courts chemins, et le nombre à côté de chaque nœud est sa distance la plus courte finale depuis A.

4 2 1 5 8 2 6 3 A B C D E F d=0 d=3 d=2 d=8 d=10 d=13
L'arbre des plus courts chemins depuis A (bleu). Les arêtes grises existent mais ne sont jamais le moyen le moins cher d'y arriver.

Voici le déroulé. À chaque étape, nous figeons le nœud non visité le plus proche (en gras) et relaxons ses voisins. signifie "pas encore atteint".

VisiteABCDEF
Départ0
A (0)042
C (2)03210
B (3)0328
D (8)03281014
E (10)03281013
F (13)03281013

Remarquez l'étape trois : visiter C a abaissé B de 4 à 3, car la route A → C → B (2 + 1) bat l'arête directe A → B (4). C'est la relaxation à l'œuvre. Voir cela se dérouler sur un graphe en direct rend le schéma immédiat, ce que vous pouvez faire dans le visualiseur d'algorithmes.

Implémentation en Python

La version propre et prête pour l'entretien utilise heapq de Python comme file de priorité. Le graphe est une liste d'adjacence associant chaque nœud à une liste de paires (voisin, poids).

import heapq

def dijkstra(graph, start):
    # Chaque nœud commence infiniment loin, sauf la source.
    distances = {node: float('inf') for node in graph}
    distances[start] = 0
    pq = [(0, start)]  # (distance jusqu'ici, nœud)

    while pq:
        dist, node = heapq.heappop(pq)

        # Une entrée périmée et plus longue pour un nœud déjà réglé : on l'ignore.
        if dist > distances[node]:
            continue

        for neighbour, weight in graph[node]:
            new_dist = dist + weight
            # Relaxation : on a trouvé un chemin moins cher vers le voisin.
            if new_dist < distances[neighbour]:
                distances[neighbour] = new_dist
                heapq.heappush(pq, (new_dist, neighbour))

    return distances

Deux détails comptent. D'abord, nous insérons une nouvelle entrée au lieu de mettre à jour le tas sur place, puis nous ignorons les entrées périmées grâce au test dist > distances[node]. Cette "suppression paresseuse" garde le code simple et c'est une pratique courante. Ensuite, l'algorithme calcule naturellement les distances vers tous les nœuds ; pour vous arrêter tôt sur une seule cible, retournez dès que vous la retirez.

Complexité en Temps et en Espace

Le coût dépend de la file de priorité. Chaque arête peut déclencher au plus une insertion, et chaque insertion ou retrait sur un tas binaire coûte O(log V).

File de prioritéTempsIdéal quand
Tas binaireO((V + E) log V)Le choix habituel, graphes creux
Tas de FibonacciO(E + V log V)Graphes denses, optimum théorique
Tableau simpleO(V²)Graphes très denses

L'espace est O(V) pour la table des distances plus la file. Pour le raisonnement derrière ces bornes et leur comparaison sur l'ensemble des algorithmes de graphes, voir le guide de la complexité des algorithmes de graphes et l'aide-mémoire d'une page.

Quand Dijkstra échoue : les Poids Négatifs

La garantie gloutonne repose entièrement sur des poids non négatifs. Ajoutez une arête négative et tout peut casser.

Supposons que l'algorithme fige un nœud parce qu'il semble le plus proche, distance 5. Plus tard, il découvre une route d'apparence plus longue qui passe par une arête -4 et atteint en fait ce nœud en 3. Trop tard : Dijkstra a déjà déclaré 5 définitif et est passé à autre chose. La réponse est fausse.

Règle à retenir : poids non négatifs, utilisez Dijkstra. Le moindre poids négatif, utilisez Bellman-Ford, qui relâche chaque arête à répétition et peut aussi détecter les cycles négatifs.

Dijkstra face aux Autres Algorithmes

Dijkstra n'est qu'un outil parmi d'autres. Choisir le bon dépend du graphe.

AlgorithmePoids négatifs ?Idéal pourTemps
BFSNon pondéré seulementPlus court chemin non pondéréO(V + E)
DijkstraNonPoids non négatifsO((V + E) log V)
Bellman-FordOuiPoids négatifs, détection de cycleO(V · E)
A*NonUne cible, avec une heuristiqueO(E) typique

Le parent le plus proche est la recherche A*, c'est-à-dire Dijkstra plus une heuristique qui oriente la recherche vers un but unique. Et Dijkstra lui-même n'est en réalité que le parcours en largeur, une simple file étant remplacée par une file de priorité.

Applications Concrètes

Regardez Dijkstra choisir son prochain nœud

La file de priorité devient limpide dès que vous la voyez tirer le nœud le moins cher, encore et encore. Exécutez Dijkstra sur un graphe en direct, pas à pas.

Ouvrir le visualiseur d'algorithmes

Foire Aux Questions

Que fait l'algorithme de Dijkstra ?

L'algorithme de Dijkstra trouve le plus court chemin d'un unique nœud source vers tous les autres nœuds d'un graphe pondéré, tant que tous les poids d'arêtes sont non négatifs. C'est la méthode standard derrière le routage, la cartographie et les protocoles réseau.

Quelle est la complexité temporelle de l'algorithme de Dijkstra ?

Avec un tas binaire comme file de priorité, l'algorithme de Dijkstra s'exécute en temps O((V + E) log V) et en espace O(V). Avec un tas de Fibonacci, il s'améliore en O(E + V log V), et avec un simple tableau il est en O(V au carré), ce qui est plus rapide sur les graphes denses.

Pourquoi l'algorithme de Dijkstra ne fonctionne-t-il pas avec des poids négatifs ?

Dijkstra fige chaque nœud dès qu'il est retiré de la file de priorité, en supposant qu'aucun chemin moins cher ne peut apparaître ensuite. Une arête négative brise cette hypothèse, car une route plus longue pourrait tout de même abaisser le coût total. Utilisez Bellman-Ford pour les graphes à poids négatifs.

L'algorithme de Dijkstra est-il identique au BFS ?

Dijkstra généralise le parcours en largeur. Le BFS utilise une simple file et trouve le plus court chemin dans les graphes non pondérés. Dijkstra remplace la file par une file de priorité minimale, de sorte qu'il étend toujours le nœud non visité le plus proche et gère les arêtes pondérées.

Ressources d'Apprentissage Supplémentaires

Voyez-le, ne vous contentez pas de lire

Dijkstra prend son sens dès que vous voyez la frontière s'étendre. Chargez un graphe, appuyez sur lecture et suivez les plus courts chemins à mesure qu'ils se forment.

Entraînez-vous avec le visualiseur d'algorithmes