Algorithme de tri topologique : Python, C++ Exemple
โก Rรฉsumรฉ intelligent
Le tri topologique ordonne les nลuds d'un graphe acyclique orientรฉ de sorte que chaque nลud apparaisse avant ceux qu'il pointe, en utilisant l'algorithme de Kahn pour sรฉlectionner de maniรจre rรฉpรฉtรฉe les nลuds de degrรฉ entrant nul.

Quโest-ce que lโalgorithme de tri topologique ?
Le tri topologique est รฉgalement connu sous le nom d'algorithme de Kahn et est un algorithme de tri populaire. En utilisant un graphe orientรฉ comme entrรฉe, Topological Sort trie les nลuds afin que chacun apparaisse avant celui vers lequel il pointe.
Cet algorithme est appliquรฉ ร un DAG (graphe acyclique orientรฉ) de sorte que chaque nลud apparaisse dans le tableau triรฉ avant tous les autres nลuds qu'il rรฉfรฉrence. Cet algorithme suit certaines rรจgles de maniรจre itรฉrative jusqu'ร ce que le tri soit terminรฉ.
Pour simplifier, regardez l'exemple suivant :
Graphique dirigรฉ
Ici, on constate que ยซ A ยป n'a pas de degrรฉ entrant. Le degrรฉ entrant correspond au nombre d'arรชtes pointant vers un nลud. ยซ B ยป et ยซ C ยป dรฉpendent de ยซ A ยป, et ยซ E ยป dรฉpend de ยซ D ยป et ยซ F ยป. Certains nลuds sont dรฉpendants d'autres.
Voici une autre reprรฉsentation du graphique ci-dessus :
Dรฉpendance de chaque nลud (Ordre Linรฉaire)
Ainsi, lorsque nous passons le DAG (Directed Acyclic Graph) au tri topologique, cela nous donnera un tableau avec un ordre linรฉaire, oรน le premier รฉlรฉment n'a aucune dรฉpendance.
Voici les รฉtapes pour ce faire:
รtape 1) Trouvez le nลud avec zรฉro arรชte entrante, un nลud avec zรฉro degrรฉ.
รtape 2) Stockez ce nลud de degrรฉ entrant nul dans une file d'attente ou une pile et supprimez-le du graphe.
รtape 3) Supprimez ensuite l'arรชte sortante de ce nลud. Cela dรฉcrรฉmentera le degrรฉ entrant du nลud suivant.
L'ordre topologique exige que la structure de donnรฉes du graphe ne contienne aucun cycle. Un graphe est considรฉrรฉ comme un DAG s'il remplit les conditions suivantes :
- Un ou plusieurs nลuds avec une valeur indegree de zรฉro.
- Le graphique ne contient aucun cycle.
Tant que le graphe contient des nลuds et reste un graphe acyclique orientรฉ (DAG), nous exรฉcuterons les trois รฉtapes prรฉcรฉdentes. Dans le cas contraire, l'algorithme rencontrera une dรฉpendance cyclique et l'algorithme de Kahn ne pourra pas trouver de nลud de degrรฉ entrant nul.
Comment fonctionne le tri topologique
Nous utiliserons ici l'algorithme de Kahn pour le tri topologique. Supposons que nous ayons le graphe suivant :
Voici les รฉtapes de l'algorithme de Kahn :
รtape 1) Calculez le degrรฉ entrant ou le bord entrant de tous les nลuds du graphique.
ร noter:
- Indegree signifie les bords dirigรฉs pointant vers le nลud.
- Outdegree dรฉsigne les arรชtes dirigรฉes provenant dโun nลud.
Voici le degrรฉ entrant et le degrรฉ sortant du graphique ci-dessus :
รtape 2) Trouvez le nลud dont le degrรฉ entrant est nul (ou qui ne reรงoit aucune arรชte entrante). Un nลud de degrรฉ entrant nul ne reรงoit aucune arรชte. Le nลud ยซ A ยป a un degrรฉ entrant nul, ce qui signifie qu'aucune arรชte ne pointe vers lui. Nous allons donc effectuer les actions suivantes :
- Supprimez ce nลud et ses arรชtes sortantes.
- Placez le nลud dans la file d'attente pour la commande.
- Mettre ร jour le nombre de degrรฉs entrants du nลud voisin de ยซ A ยป.
รtape 3) Nous devons trouver un nลud dont le degrรฉ entrant est nul. Dans cet exemple, ยซ B ยป et ยซ C ยป ont un degrรฉ entrant nul. Nous pouvons donc choisir l'un ou l'autre. Prenons ยซ B ยป et supprimons-le du graphe. Mettons ensuite ร jour les degrรฉs entrants des autres nลuds. Aprรจs ces opรฉrations, notre graphe et notre file d'attente ressembleront ร ceci :
รtape 4) Le nลud ยซ C ยป n'a pas d'arรชte entrante. Nous allons donc le supprimer du graphe et l'ajouter ร la file d'attente. Nous pouvons รฉgalement supprimer l'arรชte sortante de ยซ C ยป. Notre graphe ressemblera alors ร ceci :
รtape 5) On constate que les nลuds ยซ D ยป et ยซ F ยป ont un degrรฉ entrant nul. On va ajouter un nลud ร la file d'attente. Commenรงons par retirer ยซ D ยป. Le degrรฉ entrant du nลud ยซ E ยป sera alors de 1. Il n'y aura donc aucun nลud de D vers E. On doit procรฉder de la mรชme maniรจre pour le nลud ยซ F ยป, et le rรฉsultat sera le suivant :
รtape 6) Le degrรฉ entrant (arรชtes entrantes) et le degrรฉ sortant (arรชtes sortantes) du nลud ยซ E ยป sont dรฉsormais nuls. Nous avons donc satisfait ร toutes les conditions prรฉalables pour le nลud ยซ E ยป. Nous allons maintenant placer ยซ E ยป ร la fin de la file d'attente. Il ne reste donc plus aucun nลud et l'algorithme se termine.
Faux Code pour le tri topologique
Voici le pseudo-code du tri topologique utilisant l'algorithme de Kahn.
function TopologicalSort( Graph G ): for each node in G: calculate the indegree start = Node with 0 indegree G.remove(start) topological_list = [start] while node with 0 indegree present: topological_list.append(node) G.remove(node) // Update indegree of present nodes return topological_list
Le tri topologique peut รฉgalement รชtre implรฉmentรฉ ร l'aide du DFS (Premiรจre recherche en profondeur) mรฉthode. Cependant, cette approche est la mรฉthode rรฉcursive. L'algorithme de Kahn est plus efficace que l'approche DFS.
C++ Implรฉmentation du tri topologique
#include<bits/stdc++.h> using namespace std; class graph{ int vertices; list<int> *adjecentList; public: graph(int vertices){ this->vertices = vertices; adjecentList = new list<int>[vertices]; } void createEdge(int u, int v){ adjecentList[u].push_back(v); } void TopologicalSort(){ // filling the vector with zero initially vector<int> indegree_count(vertices,0); for(int i=0;i<vertices;i++){ list<int>::iterator itr; for(itr=adjecentList[i].begin(); itr!=adjecentList[i].end();itr++){ indegree_count[*itr]++; } } queue<int> Q; for(int i=0; i<vertices;i++){ if(indegree_count[i]==0){ Q.push(i); } } int visited_node = 0; vector<int> order; while(!Q.empty()){ int u = Q.front(); Q.pop(); order.push_back(u); list<int>::iterator itr; for(itr=adjecentList[u].begin(); itr!=adjecentList[u].end();itr++){ if(--indegree_count[*itr]==0){ Q.push(*itr); } } visited_node++; } if(visited_node!=vertices){ cout<<"There's a cycle present in the Graph.\nGiven graph is not DAG"<<endl; return; } for(int i=0; i<order.size();i++){ cout<<order[i]<<"\t"; } } }; int main(){ graph G(6); G.createEdge(0,1); G.createEdge(0,2); G.createEdge(1,3); G.createEdge(1,5); G.createEdge(2,3); G.createEdge(2,5); G.createEdge(3,4); G.createEdge(5,4); G.TopologicalSort(); }
Sortie
0 1 2 3 5 4
Python Implรฉmentation du tri topologique
from collections import defaultdict class graph: def __init__(self, vertices): self.adjacencyList = defaultdict(list) self.Vertices = vertices # No. of vertices # function to add an edge to adjacencyList def createEdge(self, u, v): self.adjacencyList[u].append(v) # The function to do Topological Sort. def topologicalSort(self): total_indegree = [0]*(self.Vertices) for i in self.adjacencyList: for j in self.adjacencyList[i]: total_indegree[j] += 1 queue = [] for i in range(self.Vertices): if total_indegree[i] == 0: queue.append(i) visited_node = 0 order = [] while queue: u = queue.pop(0) order.append(u) for i in self.adjacencyList[u]: total_indegree[i] -= 1 if total_indegree[i] == 0: queue.append(i) visited_node += 1 if visited_node != self.Vertices: print("There's a cycle present in the Graph.\nGiven graph is not DAG") else: print(order) G = graph(6) G.createEdge(0,1) G.createEdge(0,2) G.createEdge(1,3) G.createEdge(1,5) G.createEdge(2,3) G.createEdge(2,5) G.createEdge(3,4) G.createEdge(5,4) G.topologicalSort()
Sortie
[0, 1, 2, 3, 5, 4]
Graphiques cycliques de l'algorithme de tri topologique
Un graphe contenant un cycle ne peut pas รชtre topologiquement ordonnรฉ, car les dรฉpendances dans un graphe cyclique sont cycliques. Par exemple, examinez ce graphe :
Ce graphe n'est pas un DAG (graphe acyclique orientรฉ) car A, B et C forment un cycle. On remarque qu'il n'y a pas de nลud de degrรฉ entrant nul. Selon l'algorithme de Kahn, si l'on analyse le graphe ci-dessus :
- Trouvez un nลud avec zรฉro degrรฉ (pas de bords entrants).
- Supprimez ce nลud du graphe et ajoutez-le ร la file d'attente. Cependant, dans le graphe ci-dessus, aucun nลud n'a un degrรฉ entrant nul. Chaque nลud a un degrรฉ entrant supรฉrieur ร 0.
- Renvoie une file d'attente vide, car aucun nลud avec un degrรฉ entrant nul n'a รฉtรฉ trouvรฉ.
Nous pouvons dรฉtecter les cycles en utilisant l'ordre topologique avec les รฉtapes suivantes :
รtape 1) Effectuez un tri topologique.
รtape 2) Calculez le nombre total dโรฉlรฉments dans la liste triรฉe topologiquement.
รtape 3) Si le nombre d'รฉlรฉments est รฉgal au nombre total de sommets, alors il n'y a pas de cycle.
รtape 4) Si ce nombre n'est pas รฉgal au nombre de sommets, alors il existe au moins un cycle dans la structure de donnรฉes du graphe donnรฉ.
Analyse de complexitรฉ du tri topologique
Il existe deux types de complexitรฉ dans les algorithmes. Ce sont :
- Complexitรฉ temporelle
- Complexitรฉ spatiale
Ces complexitรฉs sont reprรฉsentรฉes par une fonction qui fournit une complexitรฉ gรฉnรฉrale.
Complexitรฉ temporelle: La complexitรฉ temporelle du tri topologique est identique dans tous les cas. On distingue trois scรฉnarios : le pire, le moyen et le meilleur. La complexitรฉ temporelle du tri topologique est O(E + V), oรน E reprรฉsente le nombre d'arรชtes du graphe et V le nombre de sommets.
Essayons de surmonter cette complexitรฉ :
รtape 1) Au dรฉbut, nous calculerons tous les degrรฉs. Pour ce faire, nous devons parcourir toutes les arรชtes et, dans un premier temps, nous attribuerons ร zรฉro tous les degrรฉs du sommet V. Ainsi, les รฉtapes progressives que nous accomplirons seront O(V+T).
รtape 2) Nous trouverons le nลud avec une valeur de degrรฉ nulle. Nous devons rechercher ร partir du numรฉro V du sommet. Ainsi, les รฉtapes complรฉtรฉes seront O (V).
รtape 3) Pour chaque nลud avec zรฉro degrรฉ, nous supprimerons ce nลud et dรฉcrรฉmenterons le degrรฉ. Effectuer cette opรฉration pour tous les nลuds prendra O(E).
รtape 4) Enfin, nous vรฉrifierons s'il y a un cycle ou non. Nous vรฉrifierons si le nombre total d'รฉlรฉments dans le tableau triรฉ est รฉgal au nombre total de nลuds. รa prendra O (1).
Voici donc les complexitรฉs temporelles individuelles pour chaque รฉtape du tri topologique. On peut dire que la complexitรฉ temporelle du calcul ci-dessus est O(V + E), oรน O reprรฉsente la fonction de complexitรฉ.
Complexitรฉ de l'espace: Nous avions besoin d'un espace mรฉmoire O(V) pour exรฉcuter l'algorithme de tri topologique. Voici les รฉtapes du programme qui nรฉcessitaient cet espace :
- Nous avons dรป calculer tous les degrรฉs de nลuds prรฉsents dans le graphique. Comme le graphique a un total de nลuds V, nous devons crรฉer un tableau de taille V. Ainsi, l'espace requis รฉtait O (V).
- Une structure de donnรฉes Queue a รฉtรฉ utilisรฉe pour stocker le nลud avec un degrรฉ nul. Nous avons supprimรฉ les nลuds avec un degrรฉ nul du graphique d'origine et les avons placรฉs dans la file d'attente. Pour cela, l'espace requis รฉtait O (V).
- Le tableau est nommรฉ ยซ order ยป, et il stocke les nลuds dans l'ordre topologique. Cela nรฉcessitait รฉgalement O (V) les espaces.
Il s'agissait des complexitรฉs spatiales individuelles. Il faut donc maximiser ces espaces lors de l'exรฉcution. La complexitรฉ spatiale est notรฉe O(V), oรน V reprรฉsente le nombre de sommets du graphe.
Application du tri topologique
Le tri topologique a de nombreuses applications. En voici quelques-unes :
- Il est utilisรฉ lorsqu'un Systรจme exploitation doit effectuer lโallocation des ressources.
- Recherche d'un cycle dans le graphe. On peut vรฉrifier si le graphe est un DAG ou non grรขce au tri topologique.
- Ordre des phrases dans les applications de saisie semi-automatique.
- Il est utilisรฉ pour dรฉtecter impasses.
- Diffรฉrents types de planification ou d'ordonnancement de cours utilisent le tri topologique.
- Rรฉsoudre les dรฉpendances. Par exemple, si vous essayez d'installer un package, ce package peut รฉgalement nรฉcessiter d'autres packages. L'ordre topologique dรฉcouvre tous les packages nรฉcessaires pour installer le package actuel.
- Linux utilise le tri topologique dans ยซ apt ยป pour vรฉrifier la dรฉpendance des packages.











