Topološko sortiranje: Python, C++ Primjer algoritma

Što je algoritam topološkog sortiranja?

Topološko sortiranje također je poznato kao Kahnov algoritam i popularan je algoritam sortiranja. Koristeći usmjereni graf kao ulaz, Topološko sortiranje razvrstava čvorove tako da se svaki pojavljuje ispred onog na koji pokazuje.

Ovaj se algoritam primjenjuje na DAG (usmjereni aciklički graf) tako da se svaki čvor pojavljuje u uređenom nizu prije nego što svi drugi čvorovi usmjere na njega. Ovaj algoritam opetovano slijedi neka pravila dok se sortiranje ne završi.

Radi pojednostavljenja, pogledajte sljedeći primjer:

Usmjereni graf
Usmjereni graf

Ovdje možemo vidjeti da "A" nema stupanj. To znači rub koji pokazuje na čvor. “B” i “C” imaju preduvjet “A”, zatim “E” ima preduvjet čvorove “D” i “F”. Neki od čvorova ovise o drugim čvorovima.

Evo još jednog prikaza gornjeg grafikona:

Ovisnost svakog čvora

Ovisnost svakog čvora (linearni poredak)

Dakle, kada proslijedimo DAG (usmjereni aciklički graf) topološkom sortiranju, to će nam dati niz s linearnim poretkom, gdje prvi element nema ovisnosti.

Topološki algoritam sortiranja

Ovaj primjer prikazuje grafikon s ciklusom:

Evo koraka za to:

Korak 1) Pronađite čvor s nula ulaznih rubova, čvor s nula stupnjeva.

Korak 2) Pohranite taj čvor nultog stupnja u red čekanja ili hrpu i uklonite čvor s grafikona.

Korak 3) Zatim izbrišite izlazni rub iz tog čvora.

Ovo će smanjiti broj stupnjeva za sljedeći čvor.

Topološko uređenje zahtijeva da struktura podataka grafa nema nikakav ciklus.

Graf će se smatrati DAG-om ako ispunjava ove zahtjeve:

  • Jedan ili više čvorova s ​​vrijednošću nestupnja nula.
  • Graf ne sadrži nijedan ciklus

Sve dok postoje čvorovi u Graphu i Graph je još uvijek DAG, pokrenut ćemo gornja tri koraka. U suprotnom, algoritam će pasti u cikličku ovisnost, a Kahnov algoritam neće moći pronaći čvor s nultim in-stupnjem.

Kako funkcionira topološko sortiranje

Ovdje ćemo koristiti “Kahnov algoritam” za topološko sortiranje. Recimo da imamo sljedeći grafikon:

Radovi na topološkom sortiranju

Evo koraka za Kahnov algoritam:

Korak 1) Izračunajte vanjski stupanj ili dolazni rub svih čvorova u grafu.

Bilješka:

  • Indegree znači usmjerene bridove koji pokazuju na čvor.
  • Outdegree znači usmjerene rubove koji dolaze iz čvora.

Evo stupnja i smjera gornjeg grafikona:

Radovi na topološkom sortiranju

Korak 2) Pronađite čvor s nula indestupnjeva ili nula ulaznih rubova.

Čvor s nultim stupnjem znači da rubovi ne dolaze prema tom čvoru. Čvor “A” ima nula stupnjeva, što znači da nema ruba koji pokazuje na čvor “A”.

Dakle, izvršit ćemo sljedeće radnje:

  • Uklonite ovaj čvor i njegove vanjske rubove (odlazni rubovi)
  • Stavite čvor u red čekanja za naručivanje.
  • Ažurirajte broj stupnjeva susjednog čvora "A."

Radovi na topološkom sortiranju

Korak 3) Moramo pronaći čvor s vrijednošću nestupnja nula. U ovom primjeru, "B" i "C" imaju nulti stupanj.

Ovdje možemo uzeti bilo koje od ovo dvoje. Uzmimo "B" i izbrišemo ga s grafikona.

Zatim ažurirajte vrijednosti stupnja drugih čvorova.

Nakon izvođenja ovih operacija, naš grafikon i red čekanja izgledat će ovako:

Radovi na topološkom sortiranju

Korak 4) Čvor “C” nema dolazni rub. Dakle, uklonit ćemo čvor "C" s Grafa i gurnuti ga u red čekanja.

Također možemo izbrisati rub koji izlazi iz "C".

Sada će naš grafikon izgledati ovako:

Radovi na topološkom sortiranju

Korak 5) Možemo vidjeti da čvorovi "D" i "F" imaju indegres nule. Uzet ćemo čvor i staviti ga u red čekanja.

Prvo izbacimo "D". Tada će broj stupnjevanja za čvor "E" biti 1. Sada, neće biti čvora od D do E.

Moramo učiniti isto za čvor "F", naš rezultat će biti sljedeći:

Radovi na topološkom sortiranju

Korak 6) Indegree (ulazni rubovi) i outdegree (odlazni bridovi) čvora "E" postali su nula. Dakle, ispunili smo sve preduvjete za čvor “E”.

Ovdje stavljamo "E" na kraj reda čekanja. Dakle, nemamo više čvorova, tako da algoritam ovdje završava.

Radovi na topološkom sortiranju

Pseudo kod za topološko sortiranje

Evo pseudokoda za topološko sortiranje pri korištenju Kahnova algoritma.

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 O indegree present:
    topological_list.append(node)
    G.remove(node)
    Update Indegree of present nodes
  Return topological_list

Topološko sortiranje također se može implementirati pomoću DFS-a (Prvo pretraživanje dubine) metoda. Međutim, taj pristup je rekurzivna metoda. Kahnov algoritam je učinkovitiji od DFS pristupa.

C++ Implementacija topološkog sortiranja

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

Izlaz

0       1       2       3       5       4

Python Implementacija topološkog sortiranja

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

Izlaz

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

Ciklički grafovi algoritma topološkog sortiranja

Graf koji sadrži ciklus ne može biti topološki uređen. Kako ciklički graf ima ovisnost na ciklički način.

Na primjer, provjerite ovaj grafikon:

Ciklički grafovi algoritma topološkog sortiranja

Ovaj graf nije DAG (usmjereni aciklički graf) jer A, B i C stvaraju ciklus. Ako primijetite, nema čvora s nultom vrijednošću stupnja.

Prema Kahnovom algoritmu, ako analiziramo gornji grafikon:

  • Pronađite čvor s nula indestupnjeva (bez dolazećih rubova).
  • Uklonite taj čvor s grafikona i gurnite ga u red čekanja.
    Međutim, na gornjem grafikonu ne postoji čvor s nulom u stupnjevima. Svaki čvor ima vrijednost u stupnju veću od 0.
  • Vrati prazan red jer nije mogao pronaći nijedan čvor s nulom u stupnjevima.

Možemo detektirati cikluse koristeći topološki poredak sa sljedećim koracima:

Korak 1) Izvršite topološko sortiranje.

Korak 2) Izračunajte ukupan broj elemenata u topološki sortiranoj listi.

Korak 3) Ako je broj elemenata jednak ukupnom broju vrhova, tada nema ciklusa.

Korak 4) Ako nije jednak broju vrhova, tada postoji barem jedan ciklus u danoj strukturi podataka grafa.

Analiza složenosti topološkog sortiranja

Postoje dvije vrste složenosti algoritama. oni su

  1. Složenost vremena
  2. Složenost prostora

Te su složenosti predstavljene funkcijom koja daje opću složenost.

Složenost vremena: Sva vremenska složenost je ista za topološko sortiranje. Postoje najgori, prosječni i najbolji scenariji za vremensku složenost.

Vremenska složenost za topološko sortiranje je O(E + V), ovdje E označava broj rubova u grafu, a V označava broj vrhova u grafu.

Probijmo se kroz ovu složenost:

Korak 1) Na početku ćemo izračunati sve stupnjeve. Da bismo to učinili, trebamo proći kroz sve bridove, a na početku ćemo dodijeliti sve stupnjeve V vrhova na nulu. Dakle, inkrementalni koraci koje dovršavamo bit će O(V+E).

Korak 2) Pronaći ćemo čvor s vrijednošću nultog stupnja. Trebamo tražiti od V broja vrha. Dakle, koraci će biti dovršeni O(V).

Korak 3) Za svaki čvor s nultim stupnjem, uklonit ćemo taj čvor i smanjiti indegrees. Izvođenje ove operacije za sve čvorove će potrajati O(E).

Korak 4) Na kraju ćemo provjeriti ima li ciklusa ili ne. Provjerit ćemo da li je ukupan broj elemenata u sortiranom nizu jednak ukupnom broju čvorova. Trebat će O (1).

Dakle, to je bila individualna vremenska složenost za svaki korak topološkog sortiranja ili topološkog sređivanja. Možemo reći da će vremenska složenost iz gornjeg izračuna biti O( V + E ); ovdje O znači funkciju složenosti.

Složenost prostora: Trebali smo O(V) prostore za izvođenje algoritma topološkog sortiranja.

Evo koraka u kojima nam je trebao prostor za program:

  • Morali smo izračunati sve stupnjeve čvorova prisutnih na grafikonu. Kako graf ima ukupno V čvorova, moramo stvoriti niz veličine V. Dakle, potreban prostor bio je O(V).
  • Podatkovna struktura Queue korištena je za pohranjivanje čvora s nultim stupnjem. Uklonili smo čvorove s nultim stupnjem iz originalnog grafikona i smjestili ih u red čekanja. Za to je potreban prostor bio O(V).
  • Niz se zove "red". To je pohranilo čvorove u topološkom redu. To je također zahtijevalo O(V) mjesta.

To su bile individualne složenosti prostora. Dakle, moramo maksimizirati ove prostore u vremenu izvođenja.

Prostorna složenost označava O(V), gdje V označava broj vrhova u grafu.

Primjena topološkog sortiranja

Postoji ogromna upotreba topološkog sortiranja. Ovo su neki od njih:

  • Koristi se kada Operating sustav treba izvršiti raspodjelu resursa.
  • Pronalaženje ciklusa u grafu. Topološkim sortiranjem možemo provjeriti je li graf DAG ili nije.
  • Redoslijed rečenica u aplikacijama za automatsko dovršavanje.
  • Koristi se za otkrivanje zastoja.
  • Različite vrste rasporeda ili rasporeda tečajeva koriste topološko sortiranje.
  • Rješavanje ovisnosti. Na primjer, ako pokušate instalirati paket, taj paket može također trebati druge pakete. Topološki poredak pronalazi sve potrebne pakete za instalaciju trenutnog paketa.
  • Linux koristi topološko sortiranje u "apt" za provjeru ovisnosti paketa.