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.

  • (I.e. Dรฉfinition: Le tri topologique produit un ordre linรฉaire des sommets du DAG oรน chaque arรชte orientรฉe (u, v) a u avant v.
  • (I.e. L'algorithme de Kahn : Sรฉlectionnez ร  plusieurs reprises un nล“ud sans arรชtes entrantes, ajoutez-le ร  l'ordre et dรฉcrรฉmentez le degrรฉ entrant de ses voisins.
  • ๐Ÿšซ Cycles bloquรฉs : Un graphe contenant un cycle ne peut pas รชtre triรฉ topologiquement, car aucun nล“ud n'atteint jamais un degrรฉ entrant nul ร  l'intรฉrieur du cycle.
  • ๐Ÿ’ป Code: C++ et Python les implรฉmentations utilisent une file d'attente plus un tableau de degrรฉs entrants pour calculer l'ordre en temps O(V + E).
  • (I.e. Complexitรฉ: La complexitรฉ temporelle est O(V + E) et la complexitรฉ spatiale est O(V), oรน V est le nombre de sommets et E est le nombre d'arรชtes.
  • ๏ธ Applications : La planification des tรขches et des compilations, la rรฉsolution des dรฉpendances des paquets (apt, npm), la dรฉtection des interblocages et les prรฉrequis des cours utilisent tous un ordre topologique.

Algorithme de tri topologique

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รฉ

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

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.

Algorithme de tri topologique

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 :

Travaux de tri topologique

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 :

Degrรฉ entrant et degrรฉ sortant

ร‰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 ยป.

Travaux de tri topologique

ร‰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 :

Travaux de tri topologique

ร‰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 :

Travaux de tri topologique

ร‰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 :

Travaux de tri topologique

ร‰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.

Travaux de tri topologique

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 :

Graphiques cycliques de l'algorithme de tri topologique

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 :

  1. Complexitรฉ temporelle
  2. 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.

FAQ

Le tri topologique produit un ordre linรฉaire des sommets d'un DAG de sorte que pour chaque arรชte orientรฉe de u ร  v, u apparaรฎt avant v dans l'ordre.

Tout cycle piรจge tous les nล“uds dont le degrรฉ entrant est non nul et ne s'annule jamais ; par consรฉquent, l'algorithme de Kahn ne peut pas sรฉlectionner le nล“ud suivant. Un ordre topologique valide requiert un graphe orientรฉ acyclique.

L'algorithme de Kahn utilise une file d'attente et des compteurs de degrรฉs entrants de maniรจre itรฉrative. Le tri topologique basรฉ sur un parcours en profondeur (DFS) parcourt rรฉcursivement le graphe et empile les nล“uds traitรฉs. Les deux algorithmes ont une complexitรฉ temporelle de O(V + E).

La complexitรฉ temporelle est O(V + E) car chaque sommet et arรชte est traitรฉ une seule fois. La complexitรฉ spatiale est O(V) pour le tableau des degrรฉs entrants, la file d'attente et le tableau d'ordre de sortie.

Oui. Lorsque deux nล“uds ou plus ont un degrรฉ entrant nul ร  la mรชme รฉtape, on peut choisir n'importe lequel d'entre eux en premier. Diffรฉrents ordres de sรฉlection produisent diffรฉrents ordres topologiques valides du mรชme DAG.

Les gestionnaires de paquets tels qu'apt, npm et pip utilisent l'ordre topologique pour la rรฉsolution des dรฉpendances. Les systรจmes de construction, les planificateurs de tรขches et les gestionnaires de prรฉrequis de cours s'appuient รฉgalement sur ce principe.

Les frameworks d'apprentissage automatique tels que TensorFlow et PyTorLes rรฉseaux bayรฉsiens trient topologiquement les graphes de calcul pour planifier les allers-retours. Ils requiรจrent รฉgalement un ordre topologique sur les variables.

Oui. Les outils AI Copilot, tels que GitHub Copilot, gรฉnรจrent le code de base de l'algorithme de Kahn. C++, Python, JavaLes dรฉveloppeurs doivent encore vรฉrifier la dรฉtection des cycles et la gestion correcte des files d'attente.

Rรฉsumez cet article avec :