Algoritma Pengurutan Topologi: Python, C++ Example

โšก Ringkasan Cerdas

Pengurutan Topologi mengurutkan simpul-simpul dari Graf Berarah Acyclic sehingga setiap simpul muncul sebelum simpul-simpul yang ditunjuknya, menggunakan Algoritma Kahn untuk berulang kali memilih simpul-simpul dengan derajat masuk nol.

  • ๐Ÿ“ Definisi: Pengurutan Topologi menghasilkan urutan linier simpul DAG di mana setiap sisi berarah (u, v) memiliki u sebelum v.
  • ๐Ÿ” Algoritma Kahn: Pilih berulang kali sebuah simpul dengan nol sisi masuk, tambahkan ke urutan, dan kurangi derajat masuk (indegree) dari tetangganya.
  • ๐Ÿšซ Siklus yang Diblokir: Graf yang mengandung siklus tidak dapat diurutkan secara topologis, karena tidak ada simpul yang pernah mencapai derajat masuk nol di dalam siklus tersebut.
  • ???? Code: C++ ke Python Implementasi ini menggunakan antrian ditambah array indegree untuk menghitung urutan dalam waktu O(V + E).
  • ๐Ÿ“Š Kompleksitas: Kompleksitas waktu adalah O(V + E) dan kompleksitas ruang adalah O(V), di mana V adalah jumlah simpul dan E adalah jumlah sisi.
  • ๏ธ aplikasi: Penjadwalan tugas dan pembangunan, resolusi ketergantungan paket (apt, npm), deteksi kebuntuan, dan prasyarat kursus semuanya menggunakan urutan topologi.

Algoritma Pengurutan Topologi

Apa itu Algoritma Pengurutan Topologi?

Penyortiran Topologi juga dikenal sebagai algoritma Kahn dan merupakan Algoritma Penyortiran yang populer. Dengan menggunakan grafik berarah sebagai masukan, Pengurutan Topologi mengurutkan node sehingga setiap node muncul sebelum node yang dituju.

Algoritma ini diterapkan pada DAG (Directed Acyclic Graph) sehingga setiap node muncul dalam array yang terurut sebelum semua node lain yang ditunjuk olehnya. Algoritma ini mengikuti beberapa aturan secara berulang hingga pengurutan selesai.

Untuk menyederhanakannya, lihat contoh berikut:

Grafik Sutradara

Grafik Sutradara

Di sini, kita dapat melihat bahwa โ€œAโ€ tidak memiliki indegree. Indegree berarti sisi yang mengarah ke sebuah node. โ€œBโ€ dan โ€œCโ€ memiliki prasyarat โ€œAโ€, kemudian โ€œEโ€ memiliki prasyarat โ€œDโ€ dan โ€œFโ€. Beberapa node bergantung pada node lain.

Berikut adalah representasi lain dari grafik di atas:

Ketergantungan setiap Node

Ketergantungan setiap node (Pengurutan Linier)

Jadi, ketika kita meneruskan DAG (Directed Acyclic Graph) ke pengurutan topologi, ini akan memberi kita array dengan urutan linier, di mana elemen pertama tidak memiliki ketergantungan.

Algoritma Pengurutan Topologi

Berikut adalah langkah-langkah untuk melakukannya:

Langkah 1) Temukan simpul dengan nol sisi masuk, simpul dengan nol derajat.

Langkah 2) Simpan node dengan derajat masuk nol tersebut ke dalam Antrian atau Tumpukan dan hapus node tersebut dari Graf.

Langkah 3) Kemudian hapus tepi keluar dari simpul tersebut. Ini akan mengurangi jumlah derajat masuk untuk simpul berikutnya.

Pengurutan topologi mensyaratkan bahwa struktur data graf tidak akan memiliki siklus. Sebuah graf akan dianggap sebagai DAG jika memenuhi persyaratan berikut:

  • Satu atau lebih node dengan nilai derajat masuk nol.
  • Grafik tersebut tidak mengandung siklus apa pun.

Selama masih ada node dalam Graph dan Graph tersebut masih berupa DAG, kita akan menjalankan tiga langkah di atas. Jika tidak, algoritma akan mengalami ketergantungan siklik, dan Algoritma Kahn tidak akan dapat menemukan node dengan derajat masuk nol.

Cara Kerja Penyortiran Topologi

Di sini, kita akan menggunakan โ€œAlgoritma Kahnโ€ untuk pengurutan topologi. Misalkan kita memiliki Graf berikut:

Pekerjaan Pengurutan Topologi

Berikut adalah langkah-langkah untuk Algoritma Kahn:

Langkah 1) Hitung derajat masuk atau tepi masuk dari semua node dalam Grafik.

Catatan:

  • Indegree berarti tepi berarah yang menunjuk ke node.
  • Derajat keluar berarti tepi terarah yang berasal dari sebuah simpul.

Berikut adalah indegree dan outdegree dari grafik di atas:

Derajat Masuk dan Derajat Keluar

Langkah 2) Temukan simpul dengan derajat masuk nol atau nol sisi yang masuk. Simpul dengan derajat masuk nol berarti tidak ada sisi yang menuju ke simpul tersebut. Simpul โ€œAโ€ memiliki derajat masuk nol, artinya tidak ada sisi yang mengarah ke simpul โ€œAโ€. Jadi, kita akan melakukan tindakan berikut:

  • Hapus node ini dan sisi-sisi keluarnya (sisi keluar).
  • Tempatkan node di Antrian untuk pemesanan.
  • Perbarui jumlah derajat masuk (in-degree) dari node tetangga โ€œAโ€.

Pekerjaan Pengurutan Topologi

Langkah 3) Kita perlu menemukan node dengan nilai indegree nol. Dalam contoh ini, โ€œBโ€ dan โ€œCโ€ memiliki indegree nol. Di sini, kita dapat mengambil salah satu dari keduanya. Mari kita ambil โ€œBโ€ dan hapus dari Graph. Kemudian perbarui nilai indegree node lainnya. Setelah melakukan operasi ini, Graph dan Queue kita akan terlihat seperti berikut:

Pekerjaan Pengurutan Topologi

Langkah 4) Node โ€œCโ€ tidak memiliki tepi masuk. Jadi, kita akan menghapus node โ€œCโ€ dari Graph dan memasukkannya ke dalam Queue. Kita juga dapat menghapus tepi yang keluar dari โ€œCโ€. Sekarang, Graph kita akan terlihat seperti ini:

Pekerjaan Pengurutan Topologi

Langkah 5) Kita dapat melihat bahwa node โ€œDโ€ dan โ€œFโ€ memiliki indegree nol. Kita akan mengambil sebuah node dan memasukkannya ke dalam Antrian. Mari kita keluarkan โ€œDโ€ terlebih dahulu. Maka jumlah indegree untuk node โ€œEโ€ akan menjadi 1. Sekarang, tidak akan ada node dari D ke E. Kita perlu melakukan hal yang sama untuk node โ€œFโ€, dan hasilnya akan seperti berikut:

Pekerjaan Pengurutan Topologi

Langkah 6) Derajat masuk (tepi masuk) dan derajat keluar (tepi keluar) dari node โ€œEโ€ menjadi nol. Jadi, kita telah memenuhi semua prasyarat untuk node โ€œEโ€. Di sini, kita akan menempatkan โ€œEโ€ di akhir Antrian. Jadi, kita tidak memiliki node yang tersisa, dan algoritma berakhir di sini.

Pekerjaan Pengurutan Topologi

Pseudo Code untuk Pengurutan Topologi

Berikut adalah pseudokode untuk pengurutan topologi menggunakan Algoritma 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

Pengurutan topologi juga dapat diimplementasikan menggunakan DFS (Penelusuran Pertama Kedalaman) metode. Namun pendekatan tersebut merupakan metode rekursif. Algoritma Kahn lebih efisien dibandingkan pendekatan DFS.

C++ Implementasi Penyortiran Topologi

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

Keluaran

0       1       2       3       5       4

Python Implementasi Penyortiran Topologi

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

Keluaran

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

Grafik Siklik Algoritma Pengurutan Topologi

Graf yang mengandung siklus tidak dapat diurutkan secara topologis, karena graf siklik memiliki ketergantungan secara siklik. Misalnya, perhatikan graf ini:

Grafik Siklik Algoritma Pengurutan Topologi

Graf ini bukan DAG (Directed Acyclic Graph) karena A, B, dan C membentuk siklus. Jika Anda perhatikan, tidak ada simpul dengan nilai derajat masuk nol. Menurut Algoritma Kahn, jika kita menganalisis Graf di atas:

  • Temukan simpul dengan nol derajat masuk (tidak ada sisi masuk).
  • Hapus node tersebut dari Graph dan masukkan ke dalam Queue. Namun, pada Graph di atas, tidak ada node dengan in-degree nol. Setiap node memiliki nilai in-degree lebih besar dari 0.
  • Kembalikan antrian kosong, karena tidak dapat menemukan simpul dengan derajat masuk nol.

Kita dapat mendeteksi siklus menggunakan urutan topologi dengan langkah-langkah berikut:

Langkah 1) Lakukan Penyortiran topologi.

Langkah 2) Hitung jumlah total elemen dalam daftar yang diurutkan secara topologi.

Langkah 3) Jika jumlah elemen sama dengan jumlah total simpul, maka tidak ada siklus.

Langkah 4) Jika jumlah siklus tidak sama dengan jumlah simpul, maka setidaknya ada satu siklus dalam struktur data graf yang diberikan.

Analisis Kompleksitas Sortiran Topologi

Terdapat dua jenis kompleksitas dalam algoritma. Yaitu:

  1. Kompleksitas Waktu
  2. Kompleksitas Ruang

Kompleksitas ini direpresentasikan dengan fungsi yang memberikan kompleksitas umum.

Kompleksitas Waktu: Kompleksitas waktu untuk pengurutan topologi adalah sama. Terdapat skenario terburuk, rata-rata, dan terbaik untuk kompleksitas waktu. Kompleksitas waktu untuk pengurutan topologi adalah O(E + V), di mana E adalah jumlah sisi dalam graf, dan V adalah jumlah simpul dalam graf.

Mari kita uraikan kerumitan ini:

Langkah 1) Pada awalnya, kami akan menghitung semua derajat masuk. Untuk melakukan itu, kita perlu melewati semua sisi, dan awalnya, kita akan menetapkan semua V titik dalam derajat ke nol. Jadi, langkah tambahan yang kami selesaikan adalah HAI(V+E).

Langkah 2) Kita akan menemukan node dengan nilai derajat masuk nol. Kita perlu mencari dari nomor V dari titik tersebut. Jadi, langkah-langkahnya akan selesai O (V).

Langkah 3) Untuk setiap simpul dengan derajat masuk nol, kita akan menghapus simpul tersebut dan mengurangi derajat masuknya. Melakukan operasi ini untuk semua node akan memakan waktu HAI(E).

Langkah 4) Terakhir, kami akan memeriksa apakah ada siklus atau tidak. Kami akan memeriksa apakah jumlah total elemen dalam array yang diurutkan sama dengan jumlah total node. Itu akan memakan waktu O (1).

Jadi, ini adalah kompleksitas waktu individual untuk setiap langkah pengurutan topologi atau penataan topologi. Dapat dikatakan bahwa kompleksitas waktu dari perhitungan di atas adalah O(V + E); di sini, O berarti fungsi kompleksitas.

Kompleksitas Ruang: Kami membutuhkan ruang O(V) untuk menjalankan algoritma pengurutan topologi. Berikut adalah langkah-langkah di mana kami membutuhkan ruang untuk program tersebut:

  • Kami harus menghitung semua derajat ke dalam node yang ada di Grafik. Karena Grafik memiliki total V node, kita perlu membuat array berukuran V. Jadi, ruang yang dibutuhkan adalah O (V).
  • Struktur data Antrian digunakan untuk menyimpan node dengan derajat masuk nol. Kami menghapus node dengan derajat masuk nol dari Grafik asli dan menempatkannya di Antrean. Untuk ini, ruang yang dibutuhkan adalah O (V).
  • Array tersebut diberi nama โ€œorderโ€, yang menyimpan node dalam urutan topologi. Itu juga membutuhkan O (V) spasi.

Ini adalah kompleksitas ruang individual. Jadi, kita perlu memaksimalkan ruang-ruang ini dalam waktu eksekusi. Kompleksitas ruang dilambangkan dengan O(V), di mana V berarti jumlah simpul dalam Graf.

Penerapan Pengurutan Topologi

Pengurutan Topologi memiliki banyak sekali kegunaan. Berikut beberapa di antaranya:

  • Ini digunakan ketika sebuah Operasistem ting perlu melakukan alokasi sumber daya.
  • Menemukan siklus dalam Graf. Kita dapat memvalidasi apakah Graf tersebut merupakan DAG atau bukan dengan pengurutan topologi.
  • Urutan kalimat di aplikasi pelengkapan otomatis.
  • Ini digunakan untuk mendeteksi kebuntuan.
  • Berbagai jenis penjadwalan atau penjadwalan kursus menggunakan pengurutan topologi.
  • Menyelesaikan ketergantungan. Misalnya, jika Anda mencoba menginstal suatu paket, paket tersebut mungkin juga memerlukan paket lain. Pemesanan topologi menemukan semua paket yang diperlukan untuk menginstal paket saat ini.
  • Linux menggunakan pengurutan topologi di "apt" untuk memeriksa ketergantungan paket.

Pertanyaan Umum Demo Slot

Pengurutan Topologi menghasilkan urutan linier dari simpul-simpul DAG sedemikian sehingga untuk setiap sisi berarah dari u ke v, u muncul sebelum v dalam urutan tersebut.

Setiap siklus menjebak setiap simpul di dalamnya dengan derajat masuk bukan nol yang tidak pernah turun menjadi nol, sehingga Algoritma Kahn tidak dapat memilih simpul berikutnya. Urutan topologi yang valid membutuhkan Graf Acyclic Terarah.

Algoritma Kahn menggunakan antrian dan penghitung derajat masuk secara iteratif. Pengurutan Topologi berbasis DFS melakukan rekursi melalui graf dan memasukkan simpul yang telah selesai ke dalam tumpukan. Keduanya berjalan dalam waktu O(V + E).

Kompleksitas waktu adalah O(V + E) karena setiap simpul dan sisi diproses sekali. Kompleksitas ruang adalah O(V) untuk array derajat masuk, antrian, dan array urutan keluaran.

Ya. Ketika dua atau lebih node memiliki derajat masuk nol pada langkah yang sama, salah satunya dapat dipilih terlebih dahulu. Urutan pemilihan yang berbeda menghasilkan urutan topologi valid yang berbeda dari DAG yang sama.

Pengelola paket seperti apt, npm, dan pip menggunakan urutan topologi untuk resolusi dependensi. Sistem pembangunan, penjadwal tugas, dan perencana prasyarat kursus juga bergantung padanya.

Kerangka kerja pembelajaran mesin seperti TensorFlow dan Python.Torch mengurutkan grafik komputasi secara topologis untuk menjadwalkan proses maju dan mundur. Jaringan Bayesian juga membutuhkan urutan topologis atas variabel.

Ya. Alat AI Copilot seperti GitHub Copilot menghasilkan kode standar Algoritma Kahn dalam C++, Python, atau JavaPengembang masih perlu memverifikasi deteksi siklus dan penanganan antrian yang benar.

Ringkaslah postingan ini dengan: