Menu
Coddy logo textTech

Algorithme de Dijkstra

Dernière mise à jour

L'algorithme de Dijkstra trouve le plus court chemin depuis un nœud source vers tous les autres nœuds d'un graphe dont les poids d'arête sont non négatifs. Il conserve une distance provisoire pour chaque nœud, fixe de façon répétée le nœud non fixé ayant la plus petite distance provisoire et relâche ses arêtes, en mettant à jour la distance d'un voisin chaque fois qu'un itinéraire plus court passant par le nœud courant est trouvé. Appuyez sur lecture ci-dessus pour voir les distances diminuer à mesure que chaque nœud est fixé.

L'idée clé est gloutonne : une fois le nœud non fixé le plus proche choisi, sa distance est définitive, car tout autre itinéraire vers lui devrait passer par un nœud déjà plus éloigné. Avec une file de priorité à tas binaire, Dijkstra s'exécute en temps O((V + E) log V). Il exige des poids non négatifs : utilisez Bellman-Ford si les arêtes peuvent être négatives.

Complexité en temps et en espace

ImplémentationComplexitéRemarques
Tas binaireO((V + E) log V)Le choix courant et pratique
Balayage de tableauO(V²)Plus simple ; convient aux graphes denses
EspaceO(V)Distances + file de priorité
ExigePoids non négatifsLes arêtes négatives brisent le choix glouton

Étape par étape

ÉtapeCe qui se passe
1Fixez la distance de la source à 0 et toutes les autres à l'infini.
2Choisissez le nœud non fixé ayant la plus petite distance provisoire.
3Marquez-le comme fixé : sa plus courte distance est désormais définitive.
4Pour chaque voisin, calculez distance-par-le-courant + poids de l'arête.
5Si c'est plus petit que la distance actuelle du voisin, relâchez-la.
6Répétez jusqu'à ce que tous les nœuds atteignables soient fixés.

Exemple résolu

Plus courts chemins depuis la source A sur le graphe avec les arêtes A-B=4, A-C=1, C-B=2, C-D=5, B-D=1 :

ÉtapeFixerDistancesAction
0-A=0, B=∞, C=∞, D=∞Initialiser : source A=0, toutes les autres à l'infini.
1A (0)B=4, C=1, D=∞Relâche les arêtes depuis A : fixe B=4, C=1.
2C (1)B=3, D=6Par C : B=1+2=3 améliore 4 ; D=1+5=6.
3B (3)D=4Par B : D=3+1=4 améliore 6.
4D (4)A=0, C=1, B=3, D=4Fixe D ; plus rien à relâcher. Terminé.

Quand utiliser l'algorithme de Dijkstra

À utiliser quandÀ éviter quand
Tous les poids d'arête sont non négatifsUne arête peut être négative : utilisez Bellman-Ford
Vous voulez les plus courts chemins d'une source vers tous les nœudsVous voulez les plus courts chemins entre toutes les paires : Floyd-Warshall est plus simple
Le graphe est pondéré et vous voulez des distances exactesLe graphe n'est pas pondéré : un simple BFS est plus rapide et plus simple
Vous disposez d'un bon tas ou d'une bonne file de prioritéVous voulez atteindre vite une seule cible avec une heuristique : utilisez A*

Code de Dijkstra's Algorithm

Une implémentation propre et exécutable de Dijkstra's Algorithm en Python, JavaScript, Java, C++, C. Choisissez un langage, copiez le code ou ouvrez-le préchargé dans le Playground Coddy.

Code de Dijkstra's Algorithm en Python

Python
1import heapq2
3
4def dijkstra(graph, start):5    dist = {node: float("inf") for node in graph}6    dist[start] = 07    pq = [(0, start)]8    while pq:9        d, node = heapq.heappop(pq)10        if d > dist[node]:11            continue  # stale entry, a shorter path was already found12        for neighbor, weight in graph[node]:13            new_dist = d + weight14            if new_dist < dist[neighbor]:15                dist[neighbor] = new_dist16                heapq.heappush(pq, (new_dist, neighbor))17    return dist18
19
20graph = {21    "A": [("B", 4), ("C", 1)],22    "B": [("D", 1)],23    "C": [("B", 2), ("D", 5)],24    "D": [("E", 3)],25    "E": [],26}27
28for node, d in dijkstra(graph, "A").items():29    print(f"A -> {node}: {d}")
Exécutez ce code dans le Playground Python

FAQ sur l'algorithme de Dijkstra

Quelle est la complexité en temps de l'algorithme de Dijkstra ?
Avec une file de priorité à tas binaire, il s'exécute en O((V + E) log V). Une version simple qui balaie un tableau pour trouver le minimum à chaque étape est en O(V²), ce qui peut en fait être plus rapide sur les graphes denses. Les deux utilisent un espace O(V).
Pourquoi Dijkstra ne fonctionne-t-il pas avec des poids d'arête négatifs ?
Dijkstra suppose qu'une fois le nœud non fixé le plus proche fixé, cette distance est définitive. Une arête négative pourrait créer plus tard un chemin plus court vers un nœud déjà fixé, brisant cette hypothèse. Pour les graphes à poids négatifs, utilisez l'algorithme de Bellman-Ford.
Quelle est la différence entre Dijkstra et le BFS ?
Le BFS trouve les plus courts chemins en comptant les arêtes (chaque poids d'arête vaut effectivement 1), à l'aide d'une simple file. Dijkstra généralise cela aux graphes pondérés en développant toujours le nœud ayant la plus petite distance totale, à l'aide d'une file de priorité. Sur un graphe non pondéré, les deux produisent les mêmes chemins.
Quelle est la différence entre Dijkstra et la recherche A* ?
A* est Dijkstra augmenté d'une heuristique qui estime la distance restante jusqu'à une cible, ce qui oriente la recherche vers ce but au lieu de se développer uniformément dans toutes les directions. Quand l'heuristique est nulle, A* se réduit exactement à Dijkstra. Utilisez A* lorsque vous avez une seule destination et une bonne heuristique admissible ; utilisez Dijkstra lorsque vous avez besoin des distances vers tous les nœuds.
Quand dois-je utiliser Dijkstra plutôt que Bellman-Ford ?
Utilisez Dijkstra dès que tous les poids d'arête sont non négatifs : il est plus rapide, O((V + E) log V) contre O(V·E) pour Bellman-Ford. Ne choisissez Bellman-Ford que lorsque les arêtes peuvent être négatives ou que vous devez détecter des cycles négatifs. Sur les graphes non négatifs, Dijkstra est presque toujours le meilleur choix.
Dijkstra peut-il revisiter un nœud après l'avoir fixé ?
Non : une fois un nœud fixé, sa distance est définitive et il n'est plus jamais relâché. Un piège courant dans les implémentations à tas est de laisser des entrées obsolètes dans la file de priorité après l'amélioration de la distance d'un nœud ; vous devez ignorer un nœud extrait s'il est déjà fixé (sa distance extraite dépasse la distance enregistrée). Oublier cette vérification donne encore des réponses correctes, mais gaspille du travail.
Coddy programming languages illustration

Maîtrisez les algorithmes avec Coddy

COMMENCER