Menu
Coddy logo textTech

Tri Topologique

Dernière mise à jour

Un tri topologique d'un graphe orienté acyclique (DAG) est un ordre linéaire de ses nœuds tel que pour chaque arête u → v, u vient avant v. Il répond à des questions comme « dans quel ordre puis-je exécuter ces tâches pour que chaque prérequis se termine d'abord ? ». Appuyez sur lecture ci-dessus pour voir l'algorithme de Kahn retirer les nœuds dans un ordre valide.

L'algorithme de Kahn prend à plusieurs reprises un nœud sans arêtes entrantes restantes (degré entrant 0), l'ajoute à l'ordre et retire ses arêtes sortantes, ce qui peut libérer de nouveaux nœuds de degré entrant 0. Il ne fonctionne que sur un DAG : s'il existe un cycle, certains nœuds n'atteignent jamais le degré entrant 0 et aucun ordre valide n'existe. Il s'exécute en temps O(V + E).

Complexité en temps et en espace

MesureComplexitéNotes
TempsO(V + E)Chaque nœud émis une fois, chaque arête retirée une fois
EspaceO(V)Compteurs de degré entrant + ensemble prêt + ordre
RequiertUn DAGLes cycles n'ont pas de tri topologique
RésultatNon uniqueDe nombreux ordres valides peuvent exister

Étape par étape (algorithme de Kahn)

ÉtapeCe qui se passe
1Calculer le degré entrant (nombre d'arêtes entrantes) de chaque nœud.
2Rassembler tous les nœuds de degré entrant 0 dans un ensemble prêt.
3Prendre un nœud prêt et l'ajouter à l'ordre de sortie.
4Décrémenter le degré entrant de chacun de ses successeurs.
5Tout successeur qui atteint le degré entrant 0 rejoint l'ensemble prêt.
6Répéter jusqu'à ce que l'ensemble prêt soit vide.

Exemple résolu

Tri du DAG avec les arêtes A→C, B→C, C→D, C→E, D→F, E→F (degrés entrants initiaux A:0 B:0 C:2 D:1 E:1 F:2) :

ÉtapeEnsemble prêtOrdreAction
0{A, B}[]A et B commencent avec un degré entrant 0, donc les deux sont prêts.
1{B}[A]Émettre A ; son arête A→C fait passer le degré entrant de C de 2 → 1.
2{C}[A, B]Émettre B ; son arête B→C fait passer C de 1 → 0, donc C devient prêt.
3{D, E}[A, B, C]Émettre C ; les arêtes C→D et C→E font passer D et E à 0, tous deux deviennent prêts.
4{E}[A, B, C, D]Émettre D ; son arête D→F fait passer le degré entrant de F de 2 → 1.
5{F}[A, B, C, D, E]Émettre E ; son arête E→F fait passer F de 1 → 0, donc F devient prêt.
6{}[A, B, C, D, E, F]Émettre F ; l'ensemble prêt est vide et les 6 nœuds sont ordonnés : terminé.

Quand utiliser le tri topologique

Utilisez-le quandÉvitez-le quand
Vous avez besoin d'un ordre qui respecte les dépendances (étapes de compilation, installation de paquets, prérequis de cours).Le graphe n'est pas orienté : l'ordre topologique n'est défini que pour les graphes orientés.
Le graphe est un DAG et vous voulez n'importe quel ordre linéaire valide.Le graphe peut contenir des cycles et vous avez tout de même besoin d'un ordre total (il n'en existe aucun).
Vous voulez détecter les cycles à moindre coût : un tri topologique qui échoue prouve qu'il en existe un.Vous avez besoin de l'ordre le plus court ou optimal selon un poids ; le tri topologique simple ignore les poids.
Vous traiterez l'ordre une seule fois en O(V + E).Les arêtes changent constamment et vous devez re-trier à chaque mise à jour, où une structure incrémentale convient mieux.

Code de Topological Sort

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

Code de Topological Sort en Python

Python
1from collections import deque2
3
4def topological_sort(graph):5    # Kahn's algorithm: repeatedly remove nodes with no incoming edges6    in_degree = {node: 0 for node in graph}7    for node in graph:8        for neighbor in graph[node]:9            in_degree[neighbor] += 110    queue = deque(node for node in graph if in_degree[node] == 0)11    order = []12    while queue:13        node = queue.popleft()14        order.append(node)15        for neighbor in graph[node]:16            in_degree[neighbor] -= 117            if in_degree[neighbor] == 0:18                queue.append(neighbor)19    if len(order) != len(graph):20        raise ValueError("Graph has a cycle, no topological order")21    return order22
23
24graph = {25    "shirt": ["tie", "jacket"],26    "tie": ["jacket"],27    "pants": ["shoes", "jacket"],28    "socks": ["shoes"],29    "shoes": [],30    "jacket": [],31}32
33print(" -> ".join(topological_sort(graph)))
Exécutez ce code dans le Playground Python

FAQ sur le tri topologique

À quoi sert un tri topologique ?
Il ordonne les tâches pour que chaque dépendance vienne avant ce qui en a besoin. Les usages réels incluent les systèmes de compilation et les gestionnaires de paquets (compiler les dépendances d'abord), la planification de cours avec prérequis et l'ordre d'évaluation des formules dans les tableurs.
Quelle est la complexité en temps du tri topologique ?
L'algorithme de Kahn comme l'approche fondée sur le DFS s'exécutent en temps O(V + E), car chaque nœud est traité une fois et chaque arête est examinée une fois. Ils utilisent O(V) d'espace supplémentaire.
Pourquoi le tri topologique nécessite-t-il un DAG ?
Un cycle orienté crée une contradiction : si a doit venir avant b et b doit venir avant a, aucun ordre linéaire ne satisfait les deux. Ainsi, un tri topologique existe si et seulement si le graphe est un graphe orienté acyclique. L'algorithme de Kahn détecte un cycle lorsqu'il se termine avant d'avoir émis tous les nœuds.
Quelle est la différence entre l'algorithme de Kahn et le tri topologique par DFS ?
L'algorithme de Kahn est itératif et proche du BFS : il retire à plusieurs reprises les nœuds de degré entrant 0, ce qui rend la détection de cycle et l'ordonnancement entièrement explicites. L'approche DFS visite les nœuds récursivement et place chacun en tête de l'ordre lorsque sa récursion se termine, produisant l'inverse des temps de fin. Les deux sont en O(V + E) ; celui de Kahn évite la récursion profonde et expose naturellement l'ensemble prêt, tandis que le DFS est souvent plus court à écrire.
Quand dois-je utiliser un tri topologique plutôt qu'un tri classique ?
Utilisez le tri topologique lorsque l'ordre est défini par des dépendances entre éléments plutôt que par une clé comparable. Un tri par comparaison comme le tri fusion O(n log n) ordonne par valeur ; le tri topologique ordonne selon des arêtes « doit venir avant » et, contrairement à un tri par comparaison, peut produire de nombreuses réponses valides pour la même entrée.
Le résultat d'un tri topologique est-il unique ?
Généralement non. Dès que deux nœuds ou plus sont prêts (degré entrant 0) en même temps, vous pouvez les émettre dans n'importe quel ordre, donc la plupart des DAG admettent plusieurs tris topologiques valides. L'ordre n'est unique que lorsqu'il y a exactement un nœud prêt à chaque étape, ce qui se produit lorsque le DAG forme une seule chaîne (un chemin hamiltonien).
Coddy programming languages illustration

Maîtrisez les algorithmes avec Coddy

COMMENCER