Topologisk sorteringsalgoritme: Python, C++ Eksempel

โšก Smart oppsummering

Topologisk sortering ordner nodene i en rettet asyklisk graf slik at hver node vises fรธr de den peker til, ved รฅ bruke Kahns algoritme til รฅ gjentatte ganger velge noder med null ingrad.

  • ๐Ÿ“ Definisjon: Topologisk sortering produserer en lineรฆr rekkefรธlge av DAG-hjรธrner der hver rettede kant (u, v) har u fรธr v.
  • ๐Ÿ” Kahns algoritme: Velg gjentatte ganger en node med null innkommende kanter, legg den til i ordenen, og dekrementer ingraden til naboene.
  • ๐Ÿšซ Blokkerte sykluser: En graf som inneholder en syklus kan ikke topologisk sorteres, siden ingen node noen gang nรฅr null i grader inne i syklusen.
  • ๐Ÿ’ป Code: C++ og Python Implementeringer bruker en kรธ pluss en indegree-matrise for รฅ beregne rekkefรธlgen i O(V + E)-tid.
  • ๐Ÿ“Š kompleksitet: Tidskompleksiteten er O(V + E) og romkompleksiteten er O(V), hvor V er antall toppunkter og E er antall kanter.
  • ๐Ÿ› ๏ธ Bruksomrรฅder: Oppgave- og byggeplanlegging, lรธsning av pakkeavhengigheter (apt, npm), deteksjon av vranglรฅser og forkunnskaper for kurs bruker alle topologisk rekkefรธlge.

Topologisk sorteringsalgoritme

Hva er topologisk sorteringsalgoritme?

Topologisk sortering er ogsรฅ kjent som Kahns algoritme og er en populรฆr sorteringsalgoritme. Ved รฅ bruke en rettet graf som input, sorterer Topologisk sortering nodene slik at hver vises foran den den peker til.

Denne algoritmen brukes pรฅ en DAG (Directed Acyclic Graph) slik at hver node vises i den ordnede tabellen fรธr alle andre noder den peker til. Denne algoritmen fรธlger noen regler gjentatte ganger til sorteringen er fullfรธrt.

For รฅ forenkle, se pรฅ fรธlgende eksempel:

Regissert graf

Regissert graf

Her kan vi se at ยซAยป ikke har noen ingrad. Ingrad betyr kanten som peker mot en node. ยซBยป og ยซCยป har en forutsetning av ยซAยป, deretter har ยซEยป en forutsetning av noder av typen ยซDยป og ยซFยป. Noen av nodene er avhengige av andre noder.

Her er en annen representasjon av grafen ovenfor:

Avhengighet av hver node

Avhengighet av hver node (lineรฆr rekkefรธlge)

Sรฅ nรฅr vi sender DAG (Directed Acyclic Graph) til den topologiske sorteringen, vil det gi oss en matrise med lineรฆr rekkefรธlge, der det fรธrste elementet ikke har noen avhengighet.

Topologisk sorteringsalgoritme

Her er trinnene for รฅ gjรธre dette:

Trinn 1) Finn noden med null innkommende kanter, en node med null grader.

Trinn 2) Lagre den null-i-grader-noden i en kรธ eller stabel, og fjern noden fra grafen.

Trinn 3) Slett deretter den utgรฅende kanten fra den noden. Dette vil redusere antallet grader for den neste noden.

Topologisk rekkefรธlge krever at grafens datastruktur ikke har noen syklus. En graf vil bli ansett som en DAG hvis den fรธlger disse kravene:

  • En eller flere noder med en indegree-verdi pรฅ null.
  • Grafen inneholder ingen syklus.

Sรฅ lenge det er noder i grafen og grafen fortsatt er en DAG, vil vi kjรธre de tre trinnene ovenfor. Ellers vil algoritmen falle inn i den sykliske avhengigheten, og Kahns algoritme vil ikke kunne finne en node med null in-grad.

Hvordan Topologisk sortering fungerer

Her skal vi bruke ยซKahns algoritmeยป for den topologiske sorteringen. La oss si at vi har fรธlgende graf:

Topologisk sorteringsverk

Her er trinnene for Kahns algoritme:

Trinn 1) Beregn indegreen eller innkommende kant til alle noder i grafen.

OBS:

  • Indegree betyr de rettede kantene som peker mot noden.
  • Outdegree betyr de rettede kantene som kommer fra en node.

Her er ingraden og outgraden til grafen ovenfor:

Indre grad og utre grad

Trinn 2) Finn noden med null ingrader eller null innkommende kanter. Noden med null ingrader betyr at ingen kanter kommer mot noden. Noden ยซAยป har null ingrader, noe som betyr at det ikke er noen kant som peker mot node ยซAยป. Sรฅ vi skal gjรธre fรธlgende:

  • Fjern denne noden og dens utgรฅende kanter (utgรฅende kanter).
  • Plasser noden i kรธen for bestilling.
  • Oppdater antallet grader i nabonoden til ยซAยป.

Topologisk sorteringsverk

Trinn 3) Vi mรฅ finne en node med en ingradverdi pรฅ null. I dette eksemplet har ยซBยป og ยซCยป null ingrad. Her kan vi ta en av disse to. La oss ta ยซBยป og slette den fra grafen. Deretter oppdaterer vi ingradverdiene til de andre nodene. Etter รฅ ha utfรธrt disse operasjonene, vil grafen og kรธen vรฅr se slik ut:

Topologisk sorteringsverk

Trinn 4) Noden ยซCยป har ingen innkommende kant. Sรฅ vi fjerner noden ยซCยป fra grafen og legger den inn i kรธen. Vi kan ogsรฅ slette kanten som er utgรฅende fra ยซCยป. Nรฅ vil grafen vรฅr se slik ut:

Topologisk sorteringsverk

Trinn 5) Vi kan se at nodene ยซDยป og ยซFยป har ingraden null. Vi tar en node og legger den i kรธen. La oss fรธrst fjerne ยซDยป. Da vil ingradantallet for node ยซEยป vรฆre 1. Nรฅ vil det ikke vรฆre noen node fra D til E. Vi mรฅ gjรธre det samme for node ยซFยป, og resultatet vรฅrt vil bli som fรธlger:

Topologisk sorteringsverk

Trinn 6) Ingraden (inngรฅende kanter) og utgraden (utgรฅende kanter) for noden ยซEยป ble null. Dermed har vi oppfylt alle forutsetningene for noden ยซEยป. Her setter vi ยซEยป pรฅ slutten av kรธen. Dermed har vi ingen noder igjen, og algoritmen slutter her.

Topologisk sorteringsverk

Kallenavn Code for topologisk sortering

Her er pseudokoden for den topologiske sorteringen ved bruk av Kahns algoritme.

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

Topologisk sortering kan ogsรฅ implementeres ved hjelp av DFS (Dybde fรธrste sรธk) metode. Den tilnรฆrmingen er imidlertid den rekursive metoden. Kahns algoritme er mer effektiv enn DFS-tilnรฆrmingen.

C++ Implementering av Topologisk Sortering

#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();
}

Produksjon

0       1       2       3       5       4

Python Implementering av Topologisk Sortering

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()

Produksjon

[0, 1, 2, 3, 5, 4]

Sykliske grafer av topologisk sorteringsalgoritme

En graf som inneholder en syklus kan ikke ordnes topologisk, ettersom den sykliske grafen har avhengigheten pรฅ en syklisk mรฅte. Se for eksempel denne grafen:

Sykliske grafer av topologisk sorteringsalgoritme

Denne grafen er ikke en DAG (Directed Acyclic Graph) fordi A, B og C lager en syklus. Hvis du legger merke til det, finnes det ingen node med null verdi i grader. I fรธlge Kahns algoritme, hvis vi analyserer grafen ovenfor:

  • Finn en node med null grader (ingen innkommende kanter).
  • Fjern noden fra grafen og send den til kรธen. I grafen ovenfor er det imidlertid ingen node med null grader i tommer. Hver node har en graders verdi stรธrre enn 0.
  • Returner en tom kรธ, ettersom den ikke kunne finne noen node med null grader i tommer.

Vi kan oppdage sykluser ved รฅ bruke den topologiske rekkefรธlgen med fรธlgende trinn:

Trinn 1) Utfรธr topologisk sortering.

Trinn 2) Beregn det totale antallet elementer i den topologisk sorterte listen.

Trinn 3) Hvis antallet elementer er lik det totale antallet hjรธrner, finnes det ingen syklus.

Trinn 4) Hvis det ikke er lik antall hjรธrner, er det minst รฉn syklus i den gitte grafdatastrukturen.

Kompleksitetsanalyse av topologisk sort

Det finnes to typer kompleksitet i algoritmer. De er:

  1. Tidskompleksitet
  2. Romkompleksitet

Disse kompleksitetene er representert med en funksjon som gir en generell kompleksitet.

Tidskompleksitet: All tidskompleksitet er den samme for topologisk sortering. Det finnes verst tenkelige, gjennomsnittlige og beste tenkelige scenarioer for tidskompleksitet. Tidskompleksiteten for topologisk sortering er O(E + V), der E betyr antall kanter i grafen, og V betyr antall hjรธrner i grafen.

La oss bryte gjennom denne kompleksiteten:

Trinn 1) Til รฅ begynne med vil vi beregne alle gradene. For รฅ gjรธre det mรฅ vi gรฅ gjennom alle kantene, og til รฅ begynne med vil vi tilordne alle V toppunktingrader til null. Sรฅ de trinnvise trinnene vi fullfรธrer vil vรฆre O(V+E).

Trinn 2) Vi vil finne noden med null indegree verdi. Vi mรฅ sรธke fra V-tallet til toppunktet. Sรฅ trinnene som er fullfรธrt vil vรฆre O(V).

Trinn 3) For hver node med null grader, vil vi fjerne den noden og redusere graden. Det vil ta รฅ utfรธre denne operasjonen for alle nodene O(E).

Trinn 4) Til slutt vil vi sjekke om det er noen syklus eller ikke. Vi vil sjekke om det totale antallet elementer i den sorterte matrisen er lik det totale antallet noder. Det vil ta O (1).

Sรฅ dette var de individuelle tidskompleksitetene for hvert trinn i den topologiske sorteringen eller topologiske ordningen. Vi kan si at tidskompleksiteten fra beregningen ovenfor vil vรฆre O(V + E); her betyr O kompleksitetsfunksjonen.

Romkompleksitet: Vi trengte O(V)-rom for รฅ kjรธre den topologiske sorteringsalgoritmen. Her er trinnene der vi trengte plassen til programmet:

  • Vi mรฅtte beregne alle gradene av noder som er tilstede i grafen. Siden grafen har totalt V-noder, mรฅ vi lage en matrise med stรธrrelse V. Sรฅ plassen som kreves var O(V).
  • En kรธdatastruktur ble brukt til รฅ lagre noden med null indegree. Vi fjernet nodene med null indegree fra den originale grafen og plasserte dem i kรธen. For dette var nรธdvendig plass O(V).
  • Arrayet heter ยซordenยป, som lagret nodene i topologisk rekkefรธlge. Det krevde ogsรฅ O(V) mellomrom.

Dette var de individuelle romkompleksitetene. Sรฅ vi mรฅ maksimere disse rommene i lรธpet av kjรธretiden. Romkompleksitet stรฅr for O(V), der V betyr nummeret pรฅ hjรธrnet i grafen.

Anvendelse av topologisk sortering

Topologisk sortering har stor bruk. Her er noen av dem:

  • Den brukes nรฅr en Operating system trenger รฅ utfรธre ressursallokeringen.
  • Finne en syklus i grafen. Vi kan validere om grafen er en DAG eller ikke med topologisk sortering.
  • Setningsrekkefรธlge i appene for automatisk fullfรธring.
  • Den brukes til รฅ oppdage vranglรฅs.
  • Ulike typer planlegging eller kursplanlegging bruker topologisk sortering.
  • Lรธse avhengigheter. For eksempel, hvis du prรธver รฅ installere en pakke, kan den pakken ogsรฅ trenge andre pakker. Topologisk bestilling finner ut alle nรธdvendige pakker for รฅ installere den gjeldende pakken.
  • Linux bruker den topologiske sorteringen i "apt" for รฅ sjekke avhengigheten til pakkene.

Spรธrsmรฅl og svar

Topologisk sortering produserer en lineรฆr rekkefรธlge av hjรธrnene til en DAG slik at for hver rettet kant fra u til v, vises u fรธr v i rekkefรธlgen.

Enhver syklus fanger hver node i den med en ingrad som ikke er null og som aldri faller til null, sรฅ Kahns algoritme kan ikke velge en neste node. En gyldig topologisk orden krever en rettet asyklisk graf.

Kahns algoritme bruker en kรธ og indegradtellere iterativt. DFS-basert topologisk sortering rekurserer gjennom grafen og sender ferdige noder til en stabel. Begge kjรธrer i O(V + E).

Tidskompleksiteten er O(V + E) siden hvert hjรธrne og hver kant behandles รฉn gang. Romkompleksiteten er O(V) for den ubegrensede arrayen, kรธen og utdataordre-arrayen.

Ja. Nรฅr to eller flere noder har null ingrad pรฅ samme trinn, kan begge plukkes fรธrst. Ulike plukkeordrer produserer forskjellige gyldige topologiske ordninger av samme DAG.

Pakkebehandlere som apt, npm og pip bruker topologisk rekkefรธlge for avhengighetslรธsning. Byggesystemer, oppgaveplanleggere og planleggere av forkunnskaper for kurs er ogsรฅ avhengige av det.

Maskinlรฆringsrammeverk som TensorFlow og PyTorch topologisk sorterer beregningsgrafer for รฅ planlegge fremover- og bakoverpasseringer. Bayesianske nettverk krever ogsรฅ en topologisk rekkefรธlge over variabler.

Ja. AI Copilot-verktรธy som GitHub Copilot genererer standardversjon av Kahns algoritme i C++, Pythoneller JavaUtviklere mรฅ fortsatt bekrefte syklusdeteksjon og korrekt kรธhรฅndtering.

Oppsummer dette innlegget med: