Informatique · Terminale · 6 min de lecture
Parcourir un graphe en largeur et en profondeur
Parcours en profondeur d'abord (avec une pile ou par récursivité) et en largeur d'abord (avec une file) en marquant les sommets déjà visités ; chercher un chemin entre deux sommets ; repérer la présence d'un cycle ; le parcours en largeur d'un graphe non pondéré atteint chaque sommet par un chemin ayant le moins d'arêtes possible ; exemples du labyrinthe et du routage.
Chapitre du programme : Numérique et sciences informatiques (spécialité)
Bloc 1 sur 7 · Comprendre
Comprendre : visiter chaque sommet une fois
Parcourir un graphe, c'est visiter tous les sommets que l'on peut atteindre depuis un sommet de départ, chacun une seule fois. On marque les sommets déjà visités : sans ce marquage, un cycle ferait tourner le parcours sans fin.
On représente le graphe par un dictionnaire qui associe à chaque sommet la liste de ses voisins, ici dans l'ordre alphabétique.
Parcours en largeur. On visite le départ, puis tous ses voisins, puis les voisins de ces voisins, et ainsi de suite. On utilise une file : le premier sommet entré est le premier traité.
g = {
"A": ["B", "C"],
"B": ["A", "D", "E"],
"C": ["A", "F"],
"D": ["B"],
"E": ["B", "F"],
"F": ["C", "E"],
}
def largeur(g, depart):
vus = [depart]
file = [depart]
while len(file) > 0:
s = file.pop(0)
for v in g[s]:
if v not in vus:
vus.append(v)
file.append(v)
return vus
print(largeur(g, "A"))['A', 'B', 'C', 'D', 'E', 'F']Bloc 2 sur 7 · Approfondir
Approfondir : profondeur, pile, plus court chemin
Parcours en profondeur. Depuis un sommet, on part vers son premier voisin non visité, et on s'enfonce le plus loin possible ; quand un sommet n'a plus de voisin non visité, on revient en arrière. La version récursive utilise la pile des appels (même graphe g) :
def profondeur(g, s, vus):
vus.append(s)
for v in g[s]:
if v not in vus:
profondeur(g, v, vus)
return vus
print(profondeur(g, "A", []))['A', 'B', 'D', 'E', 'F', 'C']De A, on va en B, puis en D ; D n'a pas d'autre voisin, on revient en B, on va en E, puis en F ; de F, on atteint enfin C.
On peut aussi l'écrire avec une pile explicite (on empile les voisins à l'envers pour les dépiler dans l'ordre alphabétique) :
def profondeur_pile(g, depart):
vus = []
pile = [depart]
while len(pile) > 0:
s = pile.pop()
if s not in vus:
vus.append(s)
for v in reversed(g[s]):
if v not in vus:
pile.append(v)
return vus
print(profondeur_pile(g, "A"))['A', 'B', 'D', 'E', 'F', 'C']Plus court chemin en nombre d'arêtes. Le parcours en largeur atteint chaque sommet par un chemin ayant le moins d'arêtes possible. En notant la distance de chaque sommet découvert :
def distances(g, depart):
d = {depart: 0}
file = [depart]
while len(file) > 0:
s = file.pop(0)
for v in g[s]:
if v not in d:
d[v] = d[s] + 1
file.append(v)
return d
print(distances(g, "A")){'A': 0, 'B': 1, 'C': 1, 'D': 2, 'E': 2, 'F': 2}Les parcours servent aussi à chercher un chemin entre deux sommets (le second est-il visité ?) ou à repérer un cycle (atteindre un sommet déjà visité autrement que par l'arête d'où l'on vient). Exemples : sortir d'un labyrinthe, router des paquets dans un réseau.
Bloc 3 sur 7 · Exemple
Exemple guidé : largeur et profondeur depuis B
Énoncé. Un graphe non orienté est donné par ses listes de voisins (ordre alphabétique). Dans quel ordre ses sommets sont-ils visités depuis B, en largeur, puis en profondeur ?
| Sommet | Voisins |
|---|---|
| A | C, D |
| B | C, E |
| C | A, B, E |
| D | A |
| E | B, C |
En largeur (file). On visite B et on enfile C et E. On traite C : A est nouveau (E est déjà vu). On traite E : rien de nouveau. On traite A : D est nouveau. Ordre : B, C, E, A, D.
En profondeur (récursif). De B, premier voisin C ; de C, premier voisin non visité A ; de A, D. D est sans issue, on revient en A, puis en C : il reste E. Ordre : B, C, A, D, E.
h = {
"A": ["C", "D"],
"B": ["C", "E"],
"C": ["A", "B", "E"],
"D": ["A"],
"E": ["B", "C"],
}
def largeur(g, depart):
vus = [depart]
file = [depart]
while len(file) > 0:
s = file.pop(0)
for v in g[s]:
if v not in vus:
vus.append(v)
file.append(v)
return vus
def profondeur(g, s, vus):
vus.append(s)
for v in g[s]:
if v not in vus:
profondeur(g, v, vus)
return vus
print(largeur(h, "B"))
print(profondeur(h, "B", []))['B', 'C', 'E', 'A', 'D']
['B', 'C', 'A', 'D', 'E']Bloc 4 sur 7 · Visualiser
Voir : la file du parcours en largeur depuis A
Graphe g de la leçon (arêtes A–B, A–C, B–D, B–E, C–F, E–F) :
| Étape | Sommet traité | Voisins nouveaux enfilés | File après l'étape | Visités |
|---|---|---|---|---|
| départ | — | — | A | A |
| 1 | A | B, C | B, C | A, B, C |
| 2 | B | D, E | C, D, E | A, B, C, D, E |
| 3 | C | F | D, E, F | A, B, C, D, E, F |
| 4 | D | aucun | E, F | inchangé |
| 5 | E | aucun (F déjà vu) | F | inchangé |
| 6 | F | aucun | vide | inchangé |
Continuez sur votre lancée
Vous avez découvert l’essentiel et un exemple. Retrouvez la suite du cours et les points à retenir, puis passez à l’entraînement guidé dans votre compte.
- Les formules et les repères à retenir
- Les erreurs fréquentes expliquées
- Un exercice avec des aides et sa correction
L’accès gratuit comprend les cours et exercices de votre niveau choisi.
Sources
- BO spécial n°8 du 25 juillet 2019 — programme de spécialité numérique et sciences informatiques de terminale générale, annexe (https://eduscol.education.fr/document/30010/download) — rubrique « Algorithmique », algorithmes sur les graphes
- T. H. Cormen, C. E. Leiserson, R. L. Rivest, C. Stein, Algorithmique (Introduction to Algorithms), 3e édition française, Dunod — chapitre 22, parcours en largeur et parcours en profondeur
Vous pensez avoir trouvé une erreur dans cette leçon ? Signalez-la par e-mail.