Parcours de graphes : BFS et DFS
En 1736, Leonhard Euler a montré qu'aucune promenade ne traverse chacun des sept ponts de Königsberg exactement une fois, et la théorie des graphes est née de cette réponse.
Des points et des traits
Un graphe est un ensemble de points, appelés sommets ou nœuds, reliés par des traits, appelés arêtes. L'idée est simple, et elle s'applique à une foule de choses : des villes reliées par des routes, des pages web reliées par des liens, des personnes reliées par des amitiés, les cases d'un labyrinthe reliées là où il n'y a pas de mur. Une fois qu'un problème est dessiné sous forme de graphe, la même poignée d'algorithmes peut répondre à des questions comme « puis-je aller d'ici à là ? » et « quel est le chemin le plus court ? »
Stocker un graphe dans du code
Une façon courante de stocker un graphe est la liste d'adjacence : pour chaque sommet, la liste de ses voisins. Les notes du cours 6.006 du MIT utilisent exactement cela, un tableau ou dictionnaire Adj où Adj[u] liste les sommets reliés à u. Pour le graphe ci-dessus, cela donne :
const graph = { // liste d'adjacence
A: ["B", "C"],
B: ["A", "D"],
C: ["A", "D", "E"],
D: ["B", "C", "F"],
E: ["C", "F"],
F: ["D", "E"],
};Le parcours en largeur : anneau par anneau
Le parcours en largeur (BFS, breadth-first search) explore un graphe par anneaux autour du départ. D'abord le départ lui-même, à distance 0. Puis tous ses voisins, à distance 1. Puis chaque nouveau sommet voisin de ceux-là, à distance 2, et ainsi de suite. Pour cela, il utilise une file, une file d'attente où le premier entré est le premier sorti. On prend le sommet en tête de file, on le visite et on ajoute ses voisins pas encore vus en queue de file. À partir de A dans l'exemple, le BFS visite A, puis B et C, puis D et E, puis F. Comme il avance d'un anneau à la fois, la première fois que le BFS atteint un sommet, il a trouvé un chemin avec le moins d'arêtes possible. F est à 3 arêtes de A, par exemple A, B, D, F.
function bfs(graph, start) {
const seen = new Set([start]);
const queue = [start];
const order = [];
while (queue.length) {
const u = queue.shift(); // premier entré, premier sorti
order.push(u);
for (const v of graph[u]) {
if (!seen.has(v)) { seen.add(v); queue.push(v); }
}
}
return order; // A B C D E F
}Le parcours en profondeur : aussi loin que possible, puis retour en arrière
Le parcours en profondeur (DFS, depth-first search) se comporte comme une personne qui garde une main sur le mur dans un labyrinthe. Il suit un chemin aussi loin que possible. Quand il arrive à une impasse ou à un endroit déjà vu, il revient au dernier embranchement et essaie l'option suivante. Il utilise une pile au lieu d'une file, dernier entré, premier sorti, et il s'écrit très naturellement avec la récursivité, où la pile d'appels se charge de se souvenir. À partir de A, un DFS récursif visite A, B, D, C, E, F. Le DFS atteint tous les sommets que le BFS atteint, mais le chemin qu'il suit n'est pas forcément le plus court.
function dfs(graph, u, seen = new Set(), order = []) {
seen.add(u);
order.push(u);
for (const v of graph[u]) if (!seen.has(v)) dfs(graph, v, seen, order);
return order; // A B D C E F (en profondeur)
}Fais glisser pour tourner. Fais défiler ou pince pour zoomer.
Lequel utiliser
Dans le premier labyrinthe du labo, le BFS visite 105 cases et trouve un chemin de 22 déplacements, le plus court possible. Le DFS plonge par chance vers l'arrivée et ne visite que 31 cases, mais son chemin demande 28 déplacements. Aucun n'est toujours moins coûteux. Les deux traitent chaque sommet et chaque arête un nombre fixe de fois : tous deux s'exécutent donc en temps O(V + E) pour V sommets et E arêtes. Choisis le BFS quand il te faut le moins d'étapes : le moins de coups dans un casse-tête, le moins de liens entre deux personnes. Choisis le DFS quand il faut tout explorer ou suivre des choix jusqu'au bout : vérifier que toutes les pièces d'un labyrinthe communiquent, ou essayer les coups d'un casse-tête une ligne à la fois en revenant en arrière quand on est bloqué. Quand les arêtes ont des longueurs différentes, comme les routes, aucun des deux ne suffit seul ; des méthodes comme l'algorithme de Dijkstra prolongent l'idée du BFS avec des distances.
| graphe | Des sommets reliés par des arêtes |
| sommet (nœud) | Un point d'un graphe |
| arête | Un trait qui relie deux sommets |
| liste d'adjacence | Pour chaque sommet, la liste de ses voisins |
| file | Premier entré, premier sorti ; utilisée par le BFS |
| BFS | Parcours en largeur : anneau par anneau ; trouve les chemins avec le moins d'arêtes |
| DFS | Parcours en profondeur : d'abord en profondeur, puis retour en arrière ; utilise une pile |
| O(V + E) | Le temps d'exécution du BFS et du DFS |
- Dans le graphe d'exemple, combien d'arêtes compte le plus court chemin de A à F ?
- Combien d'arêtes compte le graphe d'exemple ?
- Quelle structure de données le parcours en largeur utilise-t-il ?
- Une file (premier entré, premier sorti)
- Une pile (dernier entré, premier sorti)
- Une liste triée
- Aucune structure
- Quel parcours est sûr de trouver un chemin avec le moins d'arêtes ?
- BFS
- DFS
- Les deux, toujours
- Aucun
- Range les sommets dans l'ordre où le BFS depuis A les visite (voisins pris par ordre alphabétique).
- Range les sommets dans l'ordre où le DFS récursif depuis A les visite (voisins par ordre alphabétique).
- Sur la grille de 15 sur 9 du labo, sans aucun mur, combien de déplacements compte le plus court chemin de S (en haut à gauche) à G (en bas à droite) ?
- Pourquoi le BFS et le DFS doivent-ils se souvenir des sommets déjà vus ?
- Sinon, une boucle dans le graphe ferait tourner le parcours en rond indéfiniment
- Pour les afficher à la fin
- Pour les trier
- Ce n'est nécessaire que pour le DFS
- En quelle année Euler a-t-il résolu le problème des ponts de Königsberg ?
- 1683
- 1736
- 1843
- 1945
- Quel est le temps d'exécution du BFS sur un graphe de V sommets et E arêtes ?
- O(V + E)
- O(V × E)
- O(log V)
- O(2ⱽ)
- Tu veux connaître le plus petit nombre de liens « ami d'un ami » entre deux personnes dans un réseau social. Quel parcours ?
- BFS
- DFS
- Recherche dichotomique
- Tri fusion
- Un graphe est un ensemble de sommets reliés par des arêtes ; les listes d'adjacence le stockent.
- Le BFS utilise une file, avance anneau par anneau et trouve les chemins avec le moins d'arêtes.
- Le DFS utilise une pile (ou la récursivité), va d'abord en profondeur, puis revient en arrière.
- Les deux s'exécutent en O(V + E) et doivent se souvenir des sommets vus.
- La solution d'Euler pour les ponts de Königsberg, en 1736, a fait naître la théorie des graphes.
Sources de ce cours (11)
- MIT OpenCourseWare 6.006 Introduction to Algorithms, Spring 2020 (Demaine, Ku, Solomon)
- lecture notes 1 Introduction, 3 Sorting, 9 Breadth-First Search, 10 Depth-First Search (ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/pages/lecture-notes) and Fall 2011 lecture 13 BFS notes (ocw.mit.edu/courses/6-006-introduction-to-algorithms-fall-2011)
- Cormen, Leiserson, Rivest, Stein, Introduction to Algorithms (MIT Press)
- with the CLRS-based Khan Academy algorithms unit by Thomas Cormen and Devin Balkcom of Dartmouth (khanacademy.org/computing/computer-science/algorithms: binary search, selection sort analysis, merge sort, quicksort overview and analysis)
- MacTutor History of Mathematics, Al-Khwarizmi (mathshistory.st-andrews.ac.uk/Biographies/Al-Khwarizmi: word algorithm from the Latin title Algoritmi de numero Indorum)
- D. E. Joyce, Euclid's Elements Book VII Propositions 1 and 2 (mathcs.clarku.edu/~djoyce/elements/bookVII)
- Wolfram MathWorld, Merge Sort (mathworld.wolfram.com/MergeSort.html: proposed by John von Neumann in 1945, after Knuth 1998 p. 159)
- Stanford CS "Tony Hoare: Quicksort" (cs.stanford.edu/people/eroberts/courses/soco/projects/2008-09/tony-hoare/quicksort.html: devised while a student at Moscow State University for Russian-English machine translation with a tape dictionary, programmed in Algol 60 and published 1961; the year 1959 from the Wikipedia Quicksort article and its cited sources)
- Bodleian Libraries, Ada Lovelace (blogs.bodleian.ox.ac.uk/adalovelace: 1843 paper, Note G Bernoulli numbers)
- Fourmilab text of Menabrea's Sketch with Lovelace's notes (fourmilab.ch/babbage/sketch.html)
- Seven Bridges of Konigsberg (Euler 1736) and Tower of Hanoi (Edouard Lucas, 1883) checked against the Wikipedia articles and their cited sources.
Consulté le: 2026-10-17