Topologinen lajittelualgoritmi: Python, C++ esimerkki

โšก ร„lykรคs yhteenveto

Topologinen lajittelu jรคrjestรครค suunnatun asyklisen graafin solmut siten, ettรค jokainen solmu nรคkyy ennen niitรค, joihin se osoittaa, kรคyttรคen Kahnin algoritmia poimimaan toistuvasti solmuja, joiden epรคsuhta on nolla.

  • ๐Ÿ“ Mรครคritelmรค: Topologinen jรคrjestely tuottaa lineaarisen DAG-solmujen jรคrjestyksen, jossa jokaisella suunnatulla kaarella (u, v) on u ennen v:tรค.
  • ๐Ÿ” Kahnin algoritmi: Valitse toistuvasti solmu, jossa ei ole saapuvia kaaria, lisรครค se jรคrjestykseen ja vรคhennรค sen naapureiden sisรครคntuloastetta.
  • ๐Ÿšซ Estetyt syklit: Syklin sisรคltรคvรครค graafia ei voida topologisesti jรคrjestรครค, koska yksikรครคn solmu ei koskaan saavuta nollaa astetta syklin sisรคllรค.
  • ๐Ÿ’ป Code: C++ ja Python toteutuksissa kรคytetรครคn jonoa ja asteeltaan erillistรค taulukkoa jรคrjestyksen laskemiseen ajassa O(V + E).
  • ๐Ÿ“Š Monimutkaisuus: Aikavaativuus on O(V + E) ja avaruusvaativuus on O(V), missรค V on solmujen lukumรครคrรค ja E on kaarien lukumรครคrรค.
  • ๐Ÿ› ๏ธ Sovellukset: Tehtรคvien ja koontien ajoitus, pakettiriippuvuuksien ratkaiseminen (apt, npm), lukkiutumien tunnistus ja kurssin esitiedot kรคyttรคvรคt kaikki topologista jรคrjestystรค.

Topologinen lajittelualgoritmi

Mikรค on topologinen lajittelualgoritmi?

Topologinen lajittelu tunnetaan myรถs nimellรค Kahnin algoritmi, ja se on suosittu lajittelualgoritmi. Kรคyttรคmรคllรค suunnattua kuvaajaa syรถtteenรค Topologinen lajittelu lajittelee solmut siten, ettรค jokainen nรคkyy ennen sitรค, johon se osoittaa.

Tรคtรค algoritmia sovelletaan DAG-taulukkoon (Directed Acyclic Graph) siten, ettรค jokainen solmu esiintyy jรคrjestetyssรค taulukossa ennen kaikkia muita solmuja, joihin se osoittaa. Tรคmรค algoritmi noudattaa tiettyjรค sรครคntรถjรค toistuvasti, kunnes lajittelu on valmis.

Yksinkertaistaaksesi, katso seuraava esimerkki:

Ohjattu graafi

Ohjattu graafi

Tรคssรค nรคemme, ettรค โ€Aโ€:lla ei ole sisรครคnpรคin suuntautuvaa astetta. Sisรครคnpรคin suuntautuva aste tarkoittaa reunaa, joka osoittaa solmuun. โ€Bโ€:llรค ja โ€Cโ€:llรค on edellytys โ€Aโ€:lle, ja โ€Eโ€:llรค on edellytys โ€Dโ€:lle ja โ€Fโ€:lle. Jotkut solmut ovat riippuvaisia โ€‹โ€‹toisista solmuista.

Tรคssรค on toinen esitys yllรค olevasta kaaviosta:

Jokaisen solmun riippuvuus

Jokaisen solmun riippuvuus (lineaarinen jรคrjestys)

Joten kun siirrรคmme DAG:n (Directed Acyclic Graph) topologiseen lajitteluun, se antaa meille taulukon lineaarisella jรคrjestyksellรค, jossa ensimmรคisellรค elementillรค ei ole riippuvuutta.

Topologinen lajittelualgoritmi

Voit tehdรค tรคmรคn seuraavasti:

Vaihe 1) Etsi solmu, jolla on nolla saapuvaa reunaa, solmu, jolla on nolla astetta.

Vaihe 2) Tallenna kyseinen nolla-astesolmu jonoon tai pinoon ja poista solmu graafista.

Vaihe 3) Poista sitten kyseisen solmun lรคhtevรค reuna. Tรคmรค vรคhentรครค seuraavan solmun sisรครคnpรคin suuntautuvien asteiden mรครคrรครค.

Topologinen jรคrjestys edellyttรครค, ettรค graafin tietorakenteessa ei ole sykliรค. Graafia pidetรครคn DAG:na, jos se tรคyttรครค seuraavat vaatimukset:

  • Yksi tai useampi solmu, jonka asteen arvo on nolla.
  • Graafi ei sisรคllรค yhtรครคn sykliรค.

Niin kauan kuin graafissa on solmuja ja graafi on edelleen DAG, suoritamme yllรค olevat kolme vaihetta. Muuten algoritmi joutuu sykliseen riippuvuuteen, eikรค Kahnin algoritmi lรถydรค solmua, jonka aste on nolla.

Kuinka topologinen lajittelu toimii

Tรคssรค kรคytรคmme Kahnin algoritmia topologiseen lajitteluun. Oletetaan, ettรค meillรค on seuraava graafi:

Topologiset lajittelutyรถt

Tรคssรค ovat Kahnin algoritmin vaiheet:

Vaihe 1) Laske kaavion kaikkien solmujen inaste tai sisรครคntuleva reuna.

Huomautus:

  • Indegree tarkoittaa suunnattuja reunoja, jotka osoittavat solmuun.
  • Outdegree tarkoittaa suunnattuja reunoja, jotka tulevat solmusta.

Tรคssรค on yllรค olevan graafin sisรครคn- ja ulospรคinsuuntautuminen:

Indegree ja Outdegree

Vaihe 2) Etsi solmu, jossa on nolla sisรครคnpรคin suuntautuvaa astetta tai nolla sisรครคnpรคin suuntautuvaa kaarraa. Solmu, jossa on nolla sisรครคnpรคin suuntautuvaa astetta, tarkoittaa, ettรค solmua kohti ei ole tulossa kaaria. Solmulla "A" on nolla sisรครคnpรคin suuntautuvaa astetta, mikรค tarkoittaa, ettรค solmuun "A" ei ole osoittavaa kaarraa. Joten teemme seuraavat toimenpiteet:

  • Poista tรคmรค solmu ja sen ulkoreunat (lรคhtevรคt reunat).
  • Aseta solmu tilausjonoon.
  • Pรคivitรค "A":n naapurisolmun asteluku.

Topologiset lajittelutyรถt

Vaihe 3) Meidรคn on lรถydettรคvรค solmu, jonka sisรครคntuloaste on nolla. Tรคssรค esimerkissรค solmuilla "B" ja "C" on sisรครคntuloaste nolla. Tรคssรค voimme valita jommankumman nรคistรค kahdesta. Otetaan "B" ja poistetaan se graafista. Pรคivitetรครคn sitten muiden solmujen sisรครคntuloastearvot. Nรคiden toimintojen suorittamisen jรคlkeen graafi ja jono nรคyttรคvรคt seuraavalta:

Topologiset lajittelutyรถt

Vaihe 4) Solmulla โ€Cโ€ ei ole sisรครคntulevaa kaarretta. Joten poistamme solmun โ€Cโ€ graafista ja siirrรคmme sen jonoon. Voimme myรถs poistaa solmusta โ€Cโ€ lรคhtevรคn kaaren. Nyt graafimme nรคyttรครค tรคltรค:

Topologiset lajittelutyรถt

Vaihe 5) Nรคemme, ettรค solmujen โ€œDโ€ ja โ€œFโ€ astearvo on nolla. Laitamme yhden solmun jonoon. Poistetaan ensin โ€œDโ€. Tรคllรถin solmun โ€œEโ€ astearvo on 1. Nyt solmujen D ja E vรคlillรค ei ole solmuja. Meidรคn on tehtรคvรค sama solmulle โ€œFโ€, ja tuloksemme on seuraavanlainen:

Topologiset lajittelutyรถt

Vaihe 6) Solmun โ€Eโ€ sisรครคnpรคin suuntautuvat reunat ja ulospรคin suuntautuvat reunat nollautuivat. Nรคin ollen kaikki solmun โ€Eโ€ edellytykset ovat tรคyttyneet. Tรคssรค solmu โ€Eโ€ sijoitetaan jonon loppuun. Solmuja ei siis ole enรครค jรคljellรค, ja algoritmi pรครคttyy tรคhรคn.

Topologiset lajittelutyรถt

Pseudo Code topologista lajittelua varten

Tรคssรค on pseudokoodi topologiselle lajittelulle Kahnin algoritmia kรคyttรคen.

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

Topologinen lajittelu voidaan toteuttaa myรถs DFS:n (Syvyys Ensimmรคinen haku) menetelmรค. Tรคmรค lรคhestymistapa on kuitenkin rekursiivinen menetelmรค. Kahnin algoritmi on tehokkaampi kuin DFS-lรคhestymistapa.

C++ Topologisen lajittelun toteutus

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

ulostulo

0       1       2       3       5       4

Python Topologisen lajittelun toteutus

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

ulostulo

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

Topologisen lajittelualgoritmin sykliset kuvaajat

Syklin sisรคltรคvรครค graafia ei voida topologisesti jรคrjestรครค, koska syklisellรค graafilla on riippuvuus syklisellรค tavalla. Tarkastellaan esimerkiksi tรคtรค graafia:

Topologisen lajittelualgoritmin sykliset kuvaajat

Tรคmรค graafi ei ole DAG (Directed Acyclic Graph), koska A, B ja C muodostavat syklin. Huomaathan, ettei missรครคn solmussa ole nollaa astearvoa. Kahnin algoritmin mukaan, jos analysoimme yllรค olevaa graafia:

  • Etsi solmu, jossa on nolla astetta (ei sisรครคntulevia reunoja).
  • Poista kyseinen solmu graafista ja siirrรค se jonoon. Yllรค olevassa graafissa ei kuitenkaan ole solmua, jonka sisรครคntuloaste olisi nolla. Jokaisen solmun sisรครคntuloasteen arvo on suurempi kuin 0.
  • Palauttaa tyhjรคn jonon, koska ei lรถytรคnyt solmua, jonka sisรครคntuloaste olisi nolla.

Voimme havaita syklit kรคyttรคmรคllรค topologista jรคrjestystรค seuraavilla vaiheilla:

Vaihe 1) Suorita topologinen lajittelu.

Vaihe 2) Laske topologisesti jรคrjestetyn listan elementtien kokonaismรครคrรค.

Vaihe 3) Jos elementtien lukumรครคrรค on yhtรค suuri kuin solmujen kokonaismรครคrรค, sykliรค ei ole.

Vaihe 4) Jos se ei ole yhtรค suuri kuin solmujen lukumรครคrรค, annetussa graafin tietorakenteessa on ainakin yksi sykli.

Topologisen lajittelun monimutkaisuusanalyysi

Algoritmeja on kahdenlaisia โ€‹โ€‹monimutkaisuuksia. Ne ovat:

  1. Ajan monimutkaisuus
  2. Avaruuden monimutkaisuus

Nรคmรค monimutkaisuudet esitetรครคn funktiolla, joka tarjoaa yleisen monimutkaisuuden.

Ajan monimutkaisuus: Topologisessa lajittelussa aikakompleksisuus on aina sama. Aikakompleksisuudelle on olemassa pahin, keskimรครคrรคinen ja paras tapaus. Topologisen lajittelun aikakompleksisuus on O(E + V), jossa E tarkoittaa graafin kaarien lukumรครคrรครค ja V tarkoittaa graafin solmujen lukumรครคrรครค.

Murtaudutaanpa tรคmรคn monimutkaisuuden lรคpi:

Vaihe 1) Aluksi laskemme kaikki asteet. Tรคtรค varten meidรคn tรคytyy kรคydรค lรคpi kaikki reunat, ja aluksi mรครคritรคmme kaikki V-pistein asteet nollaan. Joten suorittamamme vaiheet ovat O(V+E).

Vaihe 2) Lรถydรคmme solmun, jonka inastearvo on nolla. Meidรคn tรคytyy etsiรค kรคrjen V-numerosta. Joten vaiheet on suoritettu O (V).

Vaihe 3) Jokaisen solmun, jolla on nolla astetta, poistamme kyseisen solmun ja vรคhennรคmme astetta. Tรคmรคn toiminnon suorittaminen kaikille solmuille kestรครค O(E).

Vaihe 4) Lopuksi tarkistamme, onko sykliรค vai ei. Tarkistamme, onko lajitellun taulukon elementtien kokonaismรครคrรค yhtรค suuri kuin solmujen kokonaismรครคrรค. Se tulee ottamaan O (1).

Nรคmรค olivat siis topologisen lajittelun tai topologisen jรคrjestรคmisen kunkin vaiheen yksittรคiset aikakompleksisuudet. Voimme sanoa, ettรค yllรค olevan laskelman mukainen aikakompleksisuus on O(V + E); tรคssรค O tarkoittaa kompleksisuusfunktiota.

Avaruuden monimutkaisuus: Tarvitsimme O(V) avaruuksia topologisen lajittelualgoritmin suorittamiseen. Tรคssรค ovat vaiheet, joissa tarvitsimme tilaa ohjelmalle:

  • Meidรคn piti laskea kaikki kaaviossa olevien solmujen asteet. Koska kaaviossa on yhteensรค V-solmuja, meidรคn on luotava joukko, jonka koko on V. Tarvittava tila oli siis O (V).
  • Jonotietorakennetta kรคytettiin solmun tallentamiseen nolla-asteella. Poistimme nolla-astetta sisรคltรคvรคt solmut alkuperรคisestรค kaaviosta ja asetimme ne jonoon. Tรคtรค varten tarvittava tila oli O (V).
  • Taulukon nimi on โ€orderโ€, ja se tallentaa solmut topologisessa jรคrjestyksessรค. Tรคmรค edellytti myรถs O (V) tilat.

Nรคmรค olivat yksittรคisiรค avaruuskompleksisuuksia. Joten meidรคn tรคytyy maksimoida nรคmรค avaruudet suorituksen aikana. Avaruuskompleksisuus on lyhenne O(V):stรค, jossa V tarkoittaa graafin solmun numeroa.

Topologisen lajittelun soveltaminen

Topologiselle lajittelulle on valtavasti kรคyttรถรค. Tรคssรค on joitakin niistรค:

  • Sitรค kรคytetรครคn, kun Operating-jรคrjestelmรค tรคytyy suorittaa resurssien allokointi.
  • Syklin lรถytรคminen graafista. Voimme varmistaa topologisella lajittelulla, onko graafi DAG vai ei.
  • Lausejรคrjestys automaattisen tรคydennyksen sovelluksissa.
  • Sitรค kรคytetรครคn havaitsemiseen umpikujaan.
  • Erilaiset aikataulutustyypit tai kurssien aikataulutus kรคyttรคvรคt topologista lajittelua.
  • Riippuvuuden ratkaiseminen. Jos esimerkiksi yritรคt asentaa paketin, se saattaa tarvita myรถs muita paketteja. Topologinen jรคrjestys selvittรครค kaikki nykyisen paketin asentamiseen tarvittavat paketit.
  • Linux kรคyttรครค topologista lajittelua "apt":ssa tarkistaakseen pakettien riippuvuuden.

UKK

Topologinen lajittelu tuottaa DAG-solmujen lineaarisen jรคrjestyksen siten, ettรค jokaisella u:sta v:hen suuntautuvalla kaarella u esiintyy jรคrjestyksessรค ennen v:tรค.

Mikรค tahansa sykli vangitsee jokaisen siinรค olevan solmun nollasta poikkeavalla sisรครคnpรคin suuntautuvalla asteella, joka ei koskaan putoa nollaksi, joten Kahnin algoritmi ei voi valita seuraavaa solmua. Pรคtevรค topologinen jรคrjestys vaatii suunnatun asyklisen graafin.

Kahnin algoritmi kรคyttรครค jonoa ja asteettomia laskureita iteratiivisesti. DFS-pohjainen topologinen lajittelu kรคy lรคpi graafin ja siirtรครค valmiit solmut pinoon. Molemmat toimivat muodossa O(V + E).

Aikavaativuus on O(V + E), koska jokainen piste ja kaari kรคsitellรครคn kerran. Avaruusvaativuus on O(V) asteittaiselle taulukolle, jonolle ja tulostusjรคrjestystaulukolle.

Kyllรค. Kun kahdella tai useammalla solmulla on nolla sisรครคnpรคin suuntautuvaa astetta samalla askeleella, kumpi tahansa voidaan valita ensin. Eri valintajรคrjestykset tuottavat saman DAG:n erilaisia โ€‹โ€‹kelvollisia topologisia jรคrjestyksiรค.

Pakettienhallinnan ohjelmat, kuten apt, npm ja pip, kรคyttรคvรคt topologista jรคrjestystรค riippuvuuksien ratkaisemiseen. Myรถs koontijรคrjestelmรคt, tehtรคvien ajoitusohjelmat ja kurssien edellytysten suunnittelijat kรคyttรคvรคt sitรค.

Koneoppimiskehykset, kuten TensorFlow ja PyTorch lajittelee laskentagraafit topologisesti aikatauluttaakseen eteen- ja taaksepรคin suuntautuvia laskentatoimia. Bayes-verkot vaativat myรถs topologisen jรคrjestyksen muuttujien yli.

Kyllรค. AI Copilot -tyรถkalut, kuten GitHub Copilot, luovat Kahnin algoritmin mallipohjan. C++, Pythontai JavaKehittรคjien on vielรค varmistettava syklien tunnistus ja jonojen oikea kรคsittely.

Tiivistรค tรคmรค viesti seuraavasti: