Struktur Data - Graf

Nama    : Aga Nafta Filadelfiano
NRP      : 5025251055
Kelas     : Struktur Data (D) 

Graf

Source Code: GitHub

1. Implementasi Adjacency Matrix

Deskripsi: 
Program ini merepresentasikan graf tak berarah menggunakan matriks dua dimensi berukuran tetap, di mana nilai 1 pada indeks baris dan kolom menunjukkan adanya koneksi antar vertex, sedangkan nilai 0 menunjukkan tidak ada koneksi.

Syntax Program:


Output:

Penjelasan Code:
class Graph {
    private:
        int mat[100][100];
        int ver;
  • class Graph: Membuat sebuah kelas bernama Graph untuk membungkus semua properti dan fungsi yang berkaitan dengan graf.

  • int mat[100][100]: Variabel private berupa array 2 dimensi (matriks) berukuran maksimal 100x100 untuk menyimpan hubungan antar-simpul (vertex).

  • int ver: Variabel untuk menyimpan jumlah simpul (vertex) yang ada pada graf.


    public:
        Graph(int v) {
            ver = v;
            
            int i, j;
            for(i = 0; i < v; i++) {
                for(j = 0; j < v; j++) {
                    mat[i][j] = 0;
                }
            }
        }
  • Graph(int v): Ini adalah constructor yang akan otomatis dipanggil saat objek graf dibuat. Parameter v menentukan jumlah simpul.

  • Nested Loop (for): Digunakan untuk melakukan inisialisasi awal. Semua elemen di dalam matriks diisi dengan angka 0, yang berarti pada awalnya belum ada jalur (edge) yang menghubungkan simpul satu sama lain.


        void addEdge(int u, int v) {
            mat[u][v] = 1;
            mat[v][u] = 1;
        }
  • void addEdge(int u, int v): Fungsi untuk menambahkan jalur (edge) yang menghubungkan simpul u dan simpul v.

  • mat[u][v] = 1 dan mat[v][u] = 1: Mengubah nilai matriks pada koordinat tersebut menjadi 1 (menandakan ada hubungan). Karena kedua arah diisi, program ini merepresentasikan Undirected Graph (Graf Tidak Berarah), di mana jika u terhubung ke v, maka v otomatis terhubung ke u.


        void display(void) {
            cout << "Adjacency Matrix" << endl;

            int i, j;
            for(i = 0; i < ver; i++) {
                for(j = 0; j < ver; j++) {
                    cout << mat[i][j] << " ";
                }
                cout << endl;
            }
        }
};
  • void display(void): Fungsi untuk mencetak representasi matriks ke layar komputer.

  • Nested Loop: Berjalan dari indeks 0 hingga ver - 1 untuk menampilkan seluruh isi matriks baris demi baris, sehingga membentuk tabel visual keterhubungan graf.


int main(void) {
    Graph g(4);

    g.addEdge(0,1);
    g.addEdge(0,2);
    g.addEdge(1,3);
    g.addEdge(2,3);

    g.display();

    return 0;
}
  • Graph g(4): Membuat objek graf baru bernama g dengan total 4 simpul (indeks 0, 1, 2, dan 3).

  • g.addEdge(...): Menghubungkan simpul-simpul sesuai angka di dalam parameter (0 dengan 1, 0 dengan 2, 1 dengan 3, dan 2 dengan 3).

  • g.display(): Memanggil fungsi cetak untuk melihat hasil akhir dari matriks yang telah dibentuk.


2. Implementasi Adjacency List

Deskripsi: 
Program ini menyimpan graf menggunakan daftar ketetanggaan berupa vector of vectors, yang lebih efisien dalam penggunaan memori dibandingkan matriks karena hanya menyimpan data vertex yang benar-benar terhubung.

Syntax Program:


Output:


Penjelasan code:
class gh {
    private:
        int v;
        vector<vector<int>> adj;
  • class gh: Membuat kelas bernama gh (singkatan dari graph) untuk membungkus seluruh properti dan fungsi graf.

  • int v: Variabel private untuk menyimpan jumlah total simpul (vertices) yang ada pada graf.

  • vector<vector<int>> adj: Menggunakan dinamika vektor di dalam vektor untuk membentuk Adjacency List. Pendekatan ini jauh lebih hemat memori dibandingkan matriks jika graf tidak memiliki terlalu banyak jalur (sparse graph), karena memori hanya dialokasikan untuk simpul yang benar-benar bertetangga.


    public:
        gh(int ver) {
            v = ver;
            adj.resize(v);
        }
  • gh(int ver): Constructor kelas yang otomatis dipanggil saat objek dibuat, menerima parameter ver sebagai jumlah simpulnya.

  • adj.resize(v): Mengubah ukuran vektor luar adj agar pas menampung sebanyak v elemen. Setiap elemen tersebut nantinya akan menjadi wadah (berupa daftar/vektor) untuk menyimpan simpul-simpul tetangganya.


        void addEdge(int u, int v) {
            adj[u].push_back(v);
            adj[v].push_back(u);
        }
  • void addEdge(int u, int v): Fungsi untuk menambahkan jalur (edge) yang menghubungkan simpul u dan simpul v.

  • push_back(): Memasukkan simpul v ke dalam daftar tetangga milik u, dan sebaliknya memasukkan u ke daftar tetangga v. Karena saling mencatat, program ini merepresentasikan Undirected Graph (Graf Tidak Berarah).

  • Catatan: Nama parameter v di fungsi ini menimpa (shadowing) variabel v milik kelas, tetapi kode tetap aman karena kompiler langsung mendeteksinya sebagai variabel lokal fungsi.


        void display(void) {
            int i;
            for(i = 0; i < v; i++) {
                cout << i << " -> ";

                for(int n : adj[i]) {
                    cout << n << " ";
                }

                cout << endl;
            }
        }
};
  • void display(void): Fungsi untuk menampilkan struktur daftar ketenagaan graf ke layar komputer.

  • Perulangan Luar (for i): Berjalan dari indeks 0 hingga v - 1 untuk mencetak nomor simpul utama (misal: 0 -> ).

  • Range-based For Loop (for(int n : adj[i])): Fitur modern C++ untuk menyusuri dan mencetak setiap simpul tetangga n yang terdaftar di dalam adj[i] satu per satu.


int main(void) {
    gh g(4);

    g.addEdge(0,1);
    g.addEdge(0,2);
    g.addEdge(1,3);
    g.addEdge(2,3);

    g.display();

    return 0;
}
  • gh g(4): Membuat objek graf g dengan total 4 simpul (dinomori dari 0, 1, 2, hingga 3).

  • g.addEdge(...): Menghubungkan simpul-simpul sesuai angka di dalam parameter (0 terhubung dengan 1 dan 2, sedangkan 3 terhubung dengan 1 dan 2).

  • g.display(): Memanggil fungsi visualisasi. Hasil cetakan di layar akan menunjukkan daftar tetangga dari masing-masing simpul.


3. Implementasi DFS

Deskripsi: 
Program ini menerapkan algoritma penelusuran graf Depth First Search yang mengeksplorasi sedalam mungkin pada satu cabang sebelum melakukan backtracking menggunakan teknik rekursi.

Syntax Program:



Output:

Penjelasan code:
class gh {
    private:
        int v;
        vector<vector<int>> adj;
        vector<bool> vis;
  • class gh: Membuat kelas bernama gh untuk merepresentasikan graf beserta struktur data pendukung jalannya algoritma DFS.

  • int v dan vector<vector<int>> adj: Menyimpan jumlah simpul (vertices) dan daftar tetangga (adjacency list) dari graf.

  • vector<bool> vis: Vektor bertipe boolean untuk mencatat status kunjungan simpul. Jika bernilai true artinya simpul sudah dikunjungi, dan false jika belum. Ini sangat penting untuk mencegah program terjebak dalam perulangan tanpa akhir (infinite loop) jika ada siklus di dalam graf.


    public:
        gh(int ver) {
            v = ver;
            adj.resize(v);
            vis.resize(v, false);
        }
  • gh(int ver): Constructor untuk menginisialisasi objek graf saat dibuat.

  • vis.resize(v, false): Mengatur ukuran vektor pelacak kunjungan vis sebanyak v elemen, sekaligus mengisi seluruh nilai awalnya dengan false karena di awal program belum ada simpul yang dikunjungi.


        void add(int u, int v) {
            adj[u].push_back(v);
            adj[v].push_back(u);
        }
  • void add(int u, int v): Fungsi untuk menambahkan jalur tidak berarah (undirected edge) yang menghubungkan simpul u dan simpul v secara timbal balik.


        void dfs(int v) {
            vis[v] = true;
            cout << v << " ";

            for(int u : adj[v]) {
                if(!vis[u]) {
                    dfs(u);
                }
            }
        }
};
  • void dfs(int v): Fungsi rekursif untuk menjalankan algoritma Depth First Search (DFS). DFS bekerja dengan prinsip menjelajahi graf sedalam mungkin ke satu cabang terlebih dahulu sebelum melakukan pelacakan balik (backtracking).

  • vis[v] = true;: Menandai simpul v yang sedang dikunjungi agar tidak diproses kembali di kemudian waktu.

  • cout << v << " ";: Mencetak simpul yang sedang aktif dikunjungi ke layar.

  • Perulangan dan Rekursi: Program akan mengecek satu per satu simpul tetangga (u) dari simpul v. Jika ditemukan tetangga yang belum dikunjungi (if(!vis[u])), program langsung melompat masuk ke tetangga tersebut dengan memanggil kembali fungsi dfs(u) secara rekursif.


int main(void) {
    gh g(5);

    g.add(0,1);
    g.add(0,2);
    g.add(1,3);
    g.add(2,4);

    cout << "DFS: ";
    g.dfs(0);

    return 0;
}
  • gh g(5): Membuat objek graf bernama g dengan total 5 simpul (indeks 0, 1, 2, 3, dan 4).

  • g.add(...): Membangun hubungan antar-simpul. Struktur graf yang terbentuk adalah: 0 terhubung ke 1 dan 2; 1 terhubung ke 3; 2 terhubung ke 4.

  • g.dfs(0): Menjalankan fungsi DFS dimulai dari simpul 0. Hasil urutan penjelajahan yang akan dicetak oleh kode ini adalah: 0 1 3 2 4.


4. Implementasi BFS

Deskripsi: 
Program ini menerapkan algoritma Breadth First Search yang menelusuri graf lapis demi lapis berdasarkan jarak terdekat dari vertex awal menggunakan struktur data antrean (queue).

Syntax Program:



Output:



Penjelasan code:
class Graph {
    private:
        int V;
        vector<vector<int>> adj;
  • class Graph: Membuat kelas bernama Graph untuk membungkus struktur data graf dan fungsi-fungsi penjelajahannya.

  • int V: Variabel private untuk menyimpan jumlah total simpul (vertices) di dalam graf.

  • vector<vector<int>> adj: Struktur data Adjacency List menggunakan vektor dinamis untuk menyimpan daftar tetangga dari setiap simpul.


    public:
        Graph(int vertices) {
            V=vertices;
            adj.resize(V);
        }

        void addEdge(int u,int v) {
            adj[u].push_back(v);
            adj[v].push_back(u);
        }
  • Graph(int vertices): Constructor yang otomatis berjalan saat objek dibuat untuk menentukan jumlah simpul sekaligus mengubah ukuran (resize) vektor adj sesuai jumlah simpul tersebut.

  • void addEdge(int u,int v): Fungsi untuk menambahkan jalur tidak berarah (undirected edge) antara simpul u dan v. Karena tidak berarah, kedua simpul saling dimasukkan ke dalam daftar tetangga masing-masing menggunakan push_back().


        void BFS(int start) {
            vector<bool> visited(V,false);
            queue<int> q;

            visited[start]=true;
            q.push(start);
  • void BFS(int start): Fungsi untuk menjalankan algoritma Breadth First Search (BFS) yang menjelajahi graf secara melebar (mengunjungi semua tetangga terdekat terlebih dahulu sebelum pergi ke tingkat berikutnya).

  • vector<bool> visited(V,false): Vektor lokal bertipe boolean berukuran V dengan nilai awal false untuk melacak simpul mana saja yang sudah dikunjungi agar tidak terjadi proses berulang.

  • queue<int> q: Struktur data antrean (queue) yang bekerja dengan prinsip FIFO (First In First Out). Antrean ini digunakan untuk mengatur urutan simpul yang akan dijelajahi.

  • Inisialisasi: Simpul awal (start) ditandai sebagai dikunjungi (visited[start]=true) dan dimasukkan ke dalam antrean q.


            while(!q.empty()) {
                int v=q.front();
                q.pop();

                cout << v << " ";

                for(int u : adj[v]) {
                    if(!visited[u]) {
                        visited[u]=true;
                        q.push(u);
                    }
                }
            }
        }
};
  • while(!q.empty()): Perulangan utama yang akan terus berjalan selama antrean tidak kosong.

  • q.front() dan q.pop(): Mengambil simpul di barisan terdepan antrean (disimpan di variabel v), lalu mengeluarkannya dari antrean.

  • cout << v << " ": Mencetak simpul yang sedang diproses ke layar komputer.

  • for(int u : adj[v]): Melakukan perulangan untuk memeriksa semua simpul tetangga (u) dari simpul v. Jika tetangga tersebut belum pernah dikunjungi (!visited[u]), maka statusnya diubah menjadi true dan dimasukkan ke dalam antrean q untuk diproses pada giliran berikutnya.


int main(void) {    
    Graph g(5);

    g.addEdge(0,1);
    g.addEdge(0,2);
    g.addEdge(1,3);
    g.addEdge(2,4);

    cout << "BFS: ";

    g.BFS(0);

    return 0;
}
  • Graph g(5): Membuat objek graf bernama g dengan total 5 simpul (indeks 0 hingga 4).

  • g.addEdge(...): Membangun hubungan antar-simpul. Struktur graf yang terbentuk adalah: 0 terhubung ke 1 dan 2; 1 terhubung ke 3; 2 terhubung ke 4.

  • g.BFS(0): Menjalankan fungsi BFS dimulai dari simpul 0. Karena BFS menjelajahi tetangga terdekat dulu baru berlanjut ke tingkat berikutnya, hasil urutan penjelajahan yang akan dicetak oleh kode ini adalah: 0 1 2 3 4.


5. Implementasi Graf Berbobot

Deskripsi: 
Program ini memodifikasi struktur penyimpanan graf untuk menyertakan bobot pada setiap sisi menggunakan pair, yang memungkinkan representasi biaya atau jarak antar vertex secara spesifik.

Syntax Program:



Output:

Penjelasan code:
class gh {
    private:
        map<char, vector<pair<char, int>>> adj;
  • class gh: Membuat kelas bernama gh (singkatan dari graph) untuk merepresentasikan graf berbobot.

  • map<char, vector<pair<char, int>>> adj: Struktur data utama berupa Adjacency List.

    • char bertindak sebagai kunci (key) untuk menyimpan nama simpul (misal: 'A', 'B').

    • vector<pair<char, int>> bertindak sebagai nilai (value) untuk menyimpan daftar simpul tetangga beserta bobot (weight) jalurnya. Di dalam pair, komponen pertama (first) adalah nama simpul tetangga, dan komponen kedua (second) adalah bobotnya.


    public:
        gh(int ver) {}
  • gh(int ver) {}: Constructor kelas. Berbeda dengan kode-kode sebelumnya, di sini parameter ver (jumlah simpul) tidak digunakan di dalam fungsi. Hal ini karena penggunaan std::map memungkinkan graf menambah simpul secara otomatis dan dinamis tanpa perlu melakukan alokasi ukuran di awal (resize).


        void add(char u, char v, int w) {
            adj[u].push_back({v, w});
            adj[v].push_back({u, w});
        }
  • void add(char u, char v, int w): Fungsi untuk menambahkan jalur antara simpul u dan v dengan bobot w.

  • push_back({v, w}): Menggunakan tanda kurung kurawal {} untuk membuat pair secara langsung (initializer list). Jalur ini didaftarkan secara timbal balik (dari u ke v dan dari v ke u), sehingga graf ini bertipe Undirected Weighted Graph (Graf Berbobot Tidak Berarah).


        void display() {
            for(auto const& [vertex, edges] : adj) {
                cout << "Vertex " << vertex << ": ";
                for(auto const& edge : edges) {
                    cout << "(" << edge.first << "," << edge.second << ") ";
                }
                cout << endl;
            }
        }
};
  • void display(): Fungsi untuk menampilkan visualisasi graf berbobot ke layar.

  • for(auto const& [vertex, edges] : adj): Menggunakan fitur modern C++17 bernama Structured Binding. Fitur ini memecah isi map secara langsung: variabel vertex mengambil data kunci (key / nama simpul) dan variabel edges mengambil data nilai (value / daftar tetangga). Karena std::map otomatis mengurutkan kuncinya, simpul akan tercetak urut abjad (A, B, C, D).

  • edge.first dan edge.second: Di dalam perulangan kedua, program mencetak pasangan simpul tetangga dan bobot jalurnya dengan format (tetangga,bobot).


int main(void) {
    gh g(4);

    g.add('A', 'B', 5);
    g.add('B', 'D', 3);
    g.add('D', 'C', 1);
    g.add('C', 'A', 2);

    g.display();

    return 0;
}
  • gh g(4): Membuat objek graf g (angka 4 dikirim ke constructor tetapi tidak memengaruhi proses).

  • g.add(...): Membangun hubungan berbobot antar-simpul:

    • Jalur A ke B dengan bobot 5.

    • Jalur B ke D dengan bobot 3.

    • Jalur D ke C dengan bobot 1.

    • Jalur C ke A dengan bobot 2.

  • g.display(): Menampilkan representasi akhir graf. Hasil cetakan di layar akan menunjukkan setiap simpul beserta semua tetangga dan bobot jalurnya masing-masing.



6. Implementasi Djikstra

Deskripsi: 
Program ini mencari jalur terpendek dari satu titik awal ke semua titik lain dalam graf berbobot dengan menggunakan priority queue untuk selalu memilih vertex dengan jarak akumulatif terkecil.

Syntax Program:


Output:

Penjelasan code:
const int INF = 1000000;
vector<pair<int, int>> graph[100];
  • const int INF = 1000000;: Mendefinisikan nilai tak hingga (infinity) yang direpresentasikan dengan angka 1.000.000. Nilai ini digunakan sebagai jarak awal bawaan sebelum jalur yang sebenarnya ditemukan.

  • vector<pair<int, int>> graph[100];: Array dari vektor yang bertindak sebagai Adjacency List. Array ini dapat menampung hingga 100 simpul, di mana setiap elemennya menyimpan pasangan (pair) berisi {simpul_tujuan, bobot_jalur}.


void dijkstra(int start, int V, const vector<string>& names) {
    vector<int> dist(V, INF);
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;

    dist[start] = 0;
    pq.push({0, start});
  • vector<int> dist(V, INF);: Membuat tabel pencatat jarak bernama dist berukuran V (jumlah simpul) dan mengisi seluruh nilai awalnya dengan INF.

  • priority_queue<... greater<...>> pq;: Membuat sebuah antrean prioritas (Min-Heap). Konfigurasi greater memastikan bahwa elemen dengan bobot/jarak terkecil akan selalu berada di urutan paling atas (top) untuk diproses duluan.

  • Inisialisasi: Jarak ke simpul asal (start) diatur menjadi 0 (dist[start] = 0), lalu dimasukkan ke dalam antrean pq dengan format {jarak, simpul}.


    while (!pq.empty()) {
        int d = pq.top().first;
        int u = pq.top().second;
        pq.pop();

        if (d > dist[u]) continue;

        for (auto edge : graph[u]) {
            int v = edge.first;
            int w = edge.second;
            if (dist[v] > dist[u] + w) {
                dist[v] = dist[u] + w;
                pq.push({dist[v], v});
            }
        }
    }
  • while (!pq.empty()): Perulangan utama algoritma yang berjalan selama antrean prioritas masih menyimpan simpul yang harus diperiksa.

  • if (d > dist[u]) continue;: Langkah optimasi untuk mengabaikan proses jika rute yang sedang diperiksa ternyata lebih panjang daripada rute terbaik yang sudah ditemukan sebelumnya.

  • Proses Relaksasi (Relaxation): Program memeriksa setiap simpul tetangga v dari simpul u. Jika ditemukan jalur baru yang lebih pendek melalui rumus dist[v] > dist[u] + w, maka jarak di tabel dist[v] akan diperbarui dengan nilai yang lebih kecil tersebut, lalu dimasukkan ke dalam antrean pq untuk dieksplorasi lebih lanjut.


    cout << "Jarak Terpendek dari " << names[start] << ":" << endl;
    for (int i = 0; i < V; i++) {
        cout << names[i] << " : " << dist[i] << endl;
    }
}
  • Mencetak Hasil: Setelah perulangan selesai dan jarak terpendek ke semua simpul berhasil dipetakan, blok ini akan mencetak nama kota tujuan beserta total jarak terpendeknya dari kota asal ke layar komputer.


int main(void) {
    int V = 3;
    vector<string> names = {"Surabaya", "Sidoarjo", "Gresik"};

    graph[0].push_back({1, 5});
    graph[1].push_back({0, 5});
    graph[0].push_back({2, 3});
    graph[2].push_back({0, 3});

    dijkstra(0, V, names);

    return 0;
}
  • Inisialisasi Data: Menentukan jumlah simpul (V = 3) dan memetakan indeks angka menjadi nama kota: 0 untuk Surabaya, 1 untuk Sidoarjo, dan 2 untuk Gresik.

  • Membangun Graf: Menghubungkan kota-kota secara timbal balik (undirected):

    • Surabaya (0) --> Sidoarjo (1) dengan bobot 5.

    • Surabaya (0) --> Gresik (2) dengan bobot 3.

  • dijkstra(0, V, names);: Memanggil fungsi Dijkstra dengan titik keberangkatan dari indeks 0 (Surabaya). Hasil akhirnya akan menampilkan jarak terpendek dari Surabaya ke Surabaya (0), ke Sidoarjo (5), dan ke Gresik (3).


7. Studi Kasus Praktikum: Sistem Pertemanan di Media Sosial

Deskripsi: 
Program ini mensimulasikan jaringan pertemanan sederhana di media sosial dengan memetakan nama pengguna ke dalam struktur graf dan menampilkan daftar teman untuk setiap individu.

Syntax Program:


Output:

Penjelasan code:
class Graph {
private:
    int v;
    vector<vector<int>> adj;
    vector<string> users;
  • class Graph: Membuat kelas bernama Graph untuk mensimulasikan jaringan pertemanan.

  • int v: Variabel private untuk menyimpan jumlah total pengguna (users) di dalam graf.

  • vector<vector<int>> adj: Struktur data Adjacency List (vektor di dalam vektor) yang menyimpan hubungan pertemanan dalam bentuk indeks angka.

  • vector<string> users: Vektor bertipe string untuk memetakan indeks angka menjadi nama pengguna yang sebenarnya (misal: indeks 0 dipetakan ke nama "Andi").


public:
    Graph(int ver, vector<string> userNames) {
        v = ver;
        users = userNames;
        adj.resize(v);
    }
  • Graph(...): Constructor untuk menginisialisasi objek graf. Fungsi ini menerima dua parameter: jumlah pengguna (ver) dan daftar nama pengguna (userNames).

  • adj.resize(v): Mengubah ukuran vektor luar adj agar sesuai dengan jumlah pengguna, sehingga setiap pengguna memiliki wadah/daftar tersendiri untuk mencatat siapa saja teman-teman mereka.


    void addEdge(int u, int v_idx) {
        adj[u].push_back(v_idx);
        adj[v_idx].push_back(u);
    }
  • void addEdge(...): Fungsi untuk menambahkan hubungan pertemanan antara pengguna di indeks u dan pengguna di indeks v_idx.

  • push_back(): Pertemanan ini bersifat timbal balik (Undirected Graph). Jika u berteman dengan v_idx, maka otomatis v_idx juga berteman dengan u, sehingga kedua indeks saling dimasukkan ke dalam daftar pertemanan masing-masing.


    void display() {
        for (int i = 0; i < v; i++) {
            cout << users[i] << " berteman dengan: ";
            for (int neighbor : adj[i]) {
                cout << users[neighbor] << " ";
            }
            cout << endl;
        }
    }
};
  • void display(): Fungsi untuk menampilkan daftar pertemanan setiap pengguna ke layar.

  • Perulangan Luar (for i): Berjalan menyusuri seluruh pengguna berdasarkan indeks angka, lalu menerjemahkannya menjadi nama asli menggunakan users[i].

  • Range-based For Loop (for neighbor : adj[i]): Mengambil setiap indeks teman (neighbor) yang terdaftar di dalam adj[i], lalu langsung mencetak nama asli dari teman tersebut melalui perintah users[neighbor].


int main(void) {
    vector<string> names = {"Andi", "Budi", "Citra", "Dina", "Eko"};
    Graph g(5, names);

    g.addEdge(0, 1);
    g.addEdge(0, 2);
    g.addEdge(1, 3);
    g.addEdge(2, 4);

    g.display();

    return 0;
}
  • names: Membuat daftar pengguna dengan pemetaan indeks: 0: Andi, 1: Budi, 2: Citra, 3: Dina, dan 4: Eko.

  • Graph g(5, names): Membuat objek graf g yang menampung 5 pengguna beserta daftar namanya.

  • g.addEdge(...): Membentuk hubungan pertemanan:

    • (0, 1): Andi berteman dengan Budi.

    • (0, 2): Andi berteman dengan Citra.

    • (1, 3): Budi berteman dengan Dina.

    • (2, 4): Citra berteman dengan Eko.

  • g.display(): Memanggil fungsi cetak untuk menampilkan hasil akhir jaringan pertemanan ke layar komputer.



LATIHAN


A. Graf 8 Vertex dengan Adjacency List

Deskripsi: 
Program ini membuat graf dengan 8 vertex yang saling terhubung membentuk siklus menggunakan adjacency list, sebagai bentuk latihan dasar alokasi memori dinamis pada graf.

Syntax Program:


Output:

Penjelasan code:
#include <iostream>
#include <vector>

using namespace std;
  • #include <iostream>: Pustaka standar C++ yang digunakan untuk operasi input dan output data (seperti perintah cout dan endl).

  • #include <vector>: Pustaka standar untuk menggunakan kontainer std::vector (array dinamis), yang ukurannya bisa bertambah atau berkurang secara otomatis saat program berjalan.

  • using namespace std;: Memungkinkan penggunaan semua fitur dalam namespace standar C++ tanpa harus menulis awalan std:: di depan setiap perintah.


class Graph {
    int V;
    vector<vector<int>> adj;
  • class Graph: Mendefinisikan sebuah kelas bernama Graph untuk membungkus properti dan fungsi-fungsi graf.

  • int V: Variabel anggota private untuk menyimpan jumlah total simpul (vertices) yang ada di dalam graf.

  • vector<vector<int>> adj: Sebuah vektor dua dimensi yang bertindak sebagai Adjacency List. Setiap indeks dari vektor luar mewakili sebuah simpul, dan vektor di dalamnya akan menyimpan daftar simpul lain yang menjadi tetangganya.


public:
    Graph(int V) : V(V), adj(V) {}
  • Graph(int V) : V(V), adj(V) {}: Ini adalah constructor kelas yang menggunakan fitur initializer list.

  • V(V): Menginisialisasi variabel anggota kelas V dengan nilai dari parameter V yang diterima.

  • adj(V): Langsung mengubah ukuran awal (resize) vektor luar adj agar berukuran sebanyak V elemen, sehingga siap digunakan untuk menampung daftar tetangga masing-masing simpul.


    void addEdge(int u, int v) { 
        adj[u].push_back(v); 
        adj[v].push_back(u); 
    }
  • void addEdge(int u, int v): Fungsi untuk menambahkan jalur (edge) yang menghubungkan simpul u dan simpul v.

  • push_back(): Memasukkan simpul v ke dalam daftar milik u, dan sebaliknya memasukkan u ke dalam daftar milik v. Karena pencatatan dilakukan di kedua belah pihak, graf ini bersifat Undirected Graph (Graf Tidak Berarah).


    void printGraph() {
        for(int i = 0; i < V; ++i) {
            cout << "Vertex " << i << ": ";
            for(int v : adj[i]) cout << v << " ";
            cout << endl;
        }
    }
};
  • void printGraph(): Fungsi untuk mencetak representasi graf ke layar komputer.

  • Perulangan Luar (for i): Berjalan menyusuri setiap simpul dari indeks 0 hingga V - 1.

  • Range-based For Loop (for(int v : adj[i])): Mengambil setiap nilai simpul tetangga v yang tersimpan di dalam daftar adj[i] satu per satu, lalu mencetaknya secara berurutan dipisahkan dengan spasi.


int main(void) {
    Graph g(8);
    g.addEdge(0, 1);
    g.addEdge(1, 2);
    g.addEdge(2, 3);
    g.addEdge(3, 4);
    g.addEdge(4, 5);
    g.addEdge(5, 6);
    g.addEdge(6, 7);
    g.addEdge(7, 0);
    g.printGraph();
    return 0;
}
  • Graph g(8): Membuat objek graf g dengan total 8 simpul (indeks angka 0 sampai 7).

  • g.addEdge(...): Menghubungkan simpul-simpul tersebut secara berantai: 0 terhubung ke 1, 1 ke 2, ... hingga akhirnya simpul 7 terhubung kembali ke simpul 0. Hubungan melingkar ini membentuk struktur graf yang disebut Cycle Graph (Graf Lingkaran/Siklus).

  • g.printGraph(): Memanggil fungsi untuk menampilkan daftar tetangga dari masing-masing simpul ke layar. Hasil keluarannya akan menunjukkan bahwa setiap simpul tepat memiliki dua tetangga (misalnya, Vertex 0: 1 7).



B. Implementasi DFS dan BFS

Deskripsi: 
Program ini menggabungkan dua algoritma penelusuran graf dalam satu kelas untuk mendemonstrasikan perbedaan urutan kunjungan antara penelusuran mendalam (DFS) dan melebar (BFS).

Syntax Program:



Output:

Penjelasan code:
#include <iostream>
#include <vector>
#include <queue>
#include <stack>

using namespace std;
  • #include <queue> dan #include <stack>: Pustaka standar C++ tambahan yang sangat penting di sini. <queue> digunakan untuk menyediakan struktur data antrean (Queue) yang dibutuhkan oleh BFS, sedangkan <stack> menyediakan tumpukan (Stack) yang digunakan oleh DFS.

  • Pustaka lainnya: <iostream> digunakan untuk urusan cetak-mencetak data (cout), dan <vector> digunakan untuk membuat larik dinamis sebagai basis dari Adjacency List.


class Graph {
    int V;
    vector<vector<int>> adj;
public:
    Graph(int V) : V(V), adj(V) {}
    void addEdge(int u, int v) { adj[u].push_back(v); adj[v].push_back(u); }
  • Graph(int V) : V(V), adj(V) {}: Constructor ringkas yang langsung menginisialisasi jumlah simpul total (V) sekaligus memesan ruang memori pada vektor adj sebanyak V elemen.

  • void addEdge(int u, int v): Fungsi untuk mendaftarkan hubungan bertetangga antara simpul u dan v. Karena data dimasukkan ke daftar milik kedua belah pihak, graf ini bersifat Undirected Graph (Graf Tidak Berarah).


    void BFS(int start) {
        vector<bool> visited(V, false);
        queue<int> q;
        visited[start] = true; q.push(start);
        cout << "BFS: ";
        while(!q.empty()) {
            int u = q.front(); q.pop(); cout << u << " ";
            for(int v : adj[u]) if(!visited[v]) { visited[v]=true; q.push(v); }
        }
        cout << endl;
    }
  • Metode BFS: Menjelajahi graf secara melebar. Algoritma ini akan mengunjungi semua simpul tetangga terdekat dari simpul aktif terlebih dahulu sebelum bergerak ke tingkat (level) berikutnya.

  • queue<int> q: Menggunakan antrean berbasis FIFO (First In First Out). Simpul awal (start) dimasukkan ke antrean dan langsung ditandai visited = true.

  • Mekanisme Kerja: Selama antrean tidak kosong, simpul terdepan diambil (q.front()), dikeluarkan dari antrean, lalu dicetak ke layar. Setelah itu, program akan memeriksa semua tetangga dari simpul tersebut. Tetangga yang belum pernah dikunjungi akan langsung ditandai visited = true dan dimasukkan ke dalam antrean untuk diproses nanti.


    void DFS(int start) {
        vector<bool> visited(V, false);
        stack<int> s;
        s.push(start);
        cout << "DFS: ";
        while(!s.empty()) {
            int u = s.top(); s.pop();
            if(!visited[u]) { visited[u]=true; cout << u << " "; }
            for(int v : adj[u]) if(!visited[v]) s.push(v);
        }
        cout << endl;
    }
};
  • Metode DFS: Menjelajahi graf secara mendalam. Algoritma ini akan terus bergerak menyusuri satu cabang graf hingga mencapai titik buntu sebelum akhirnya melakukan pelacakan balik (backtracking).

  • stack<int> s: Berbeda dengan implementasi DFS pada umumnya yang menggunakan fungsi rekursif, fungsi DFS di kode ini menggunakan tumpukan (Stack) eksplisit yang bekerja dengan prinsip LIFO (Last In First Out).

  • Mekanisme Kerja: Simpul paling atas tumpukan diambil (s.top()) lalu dikeluarkan. Jika simpul tersebut belum pernah dikunjungi, barulah ia ditandai true dan dicetak ke layar. Setelah itu, semua simpul tetangganya yang belum dikunjungi akan dimasukkan ke dalam tumpukan. Karena sifat LIFO, tetangga yang terakhir dimasukkan justru akan dieksplorasi lebih dalam terlebih dahulu pada perulangan berikutnya.


int main() {
    Graph g(8);
    g.addEdge(0, 1); g.addEdge(0, 2); g.addEdge(1, 3);
    g.BFS(0);
    g.DFS(0);
    return 0;
}
  • Graph g(8): Membuat sebuah objek graf bernama g dengan alokasi total 8 simpul (indeks 0 sampai 7).

  • g.addEdge(...): Menghubungkan simpul 0 dengan 1, simpul 0 dengan 2, dan simpul 1 dengan 3.

  • Eksekusi Penjelajahan: Memanggil fungsi BFS dan DFS dengan titik keberangkatan dari simpul 0:

    • Hasil BFS: 0 1 2 3 (Simpul 0 mengecek tetangga terdekatnya yaitu 1 dan 2 terlebih dahulu, baru berlanjut ke simpul 3).

    • Hasil DFS: 0 2 1 3 (Arah urutan penjelajahan bisa bervariasi tergantung urutan masuknya data ke dalam stack, namun polanya akan selalu menghabiskan satu jalur terdalam terlebih dahulu).


C. Modifikasi menjadi Weighted Graph

Deskripsi: 
Program ini melakukan modifikasi pada graf agar setiap sisi memiliki nilai bobot numerik, yang merupakan langkah persiapan untuk mengimplementasikan algoritma jalur terpendek.

Syntax Program:


Output:


Penjelasan code:
#include <iostream>
#include <vector>

using namespace std;

typedef pair<int, int> pii;
  • #include <iostream> dan #include <vector>: Pustaka standar C++ yang digunakan untuk menangani proses input-output (cout) dan array dinamis (vector).

  • typedef pair<int, int> pii;: Membuat alias nama (tipedef) baru bernama pii untuk menyingkat penulisan pair<int, int>. Di dalam graf berbobot, struktur pair (pasangan) ini sangat praktis untuk menyimpan dua informasi sekaligus: data pertama (first) sebagai simpul tetangga, dan data kedua (second) sebagai bobot (weight) jalurnya.


struct WeightedGraph {
    int V;
    vector<vector<pii>> adj;
    WeightedGraph(int V) : V(V), adj(V) {}
  • struct WeightedGraph: Mendefinisikan struktur data untuk graf berbobot. Berbeda dengan class, secara default seluruh isi (variabel dan fungsi) di dalam struct bersifat publik (public).

  • int V: Variabel untuk menyimpan jumlah total simpul (vertices) yang ada di dalam graf.

  • vector<vector<pii>> adj: Struktur data Adjacency List berupa vektor dua dimensi yang menampung elemen tipe pii (pair). Setiap indeks dari vektor luar mewakili satu simpul, dan di dalamnya terdapat daftar pasangan tetangga beserta bobotnya.

  • WeightedGraph(int V) : V(V), adj(V) {}: Constructor ringkas menggunakan initializer list untuk mengisi variabel V sekaligus langsung memesan ukuran awal vektor adj sebanyak V elemen.


    void addEdge(int u, int v, int w) { 
        adj[u].push_back({v, w}); 
        adj[v].push_back({u, w}); 
    }
  • void addEdge(int u, int v, int w): Fungsi untuk menambahkan jalur (edge) yang menghubungkan simpul u dan simpul v dengan bobot sebesar w.

  • push_back({v, w}): Membuat objek pair secara instan menggunakan kurung kurawal {} lalu memasukkannya ke dalam list. Karena jalur ini dicatat secara timbal balik (di list milik u maupun milik v), graf ini bersifat Undirected Weighted Graph (Graf Berbobot Tidak Berarah).


    void print() {
        for(int i = 0; i < V; ++i) {
            cout << "Vertex " << i << ": ";
            for(auto& edge : adj[i]) cout << "(" << edge.first << ",w=" << edge.second << ") ";
            cout << endl;
        }
    }
};
  • void print(): Fungsi untuk menampilkan visualisasi adjacency list berbobot ke layar komputer.

  • Perulangan Luar (for i): Berjalan menyusuri setiap simpul yang ada, dari indeks 0 hingga V - 1.

  • Range-based For Loop (for(auto& edge : adj[i])): Berjalan membaca setiap pair jalur yang terhubung pada simpul i secara referensi (&) agar lebih cepat dan hemat memori.

  • edge.first dan edge.second: edge.first digunakan untuk mengambil nomor simpul tetangga, sedangkan edge.second digunakan untuk mengambil nilai bobot (w) dari jalur tersebut.


int main() {
    WeightedGraph wg(8);
    wg.addEdge(0, 1, 5);
    wg.print();
    return 0;
}
  • WeightedGraph wg(8): Membuat objek graf berbobot bernama wg dengan total alokasi 8 simpul (indeks 0 sampai 7).

  • wg.addEdge(0, 1, 5): Menghubungkan simpul 0 dengan simpul 1 dan memberikan bobot jalur sebesar 5.

  • wg.print(): Memanggil fungsi untuk mencetak struktur graf. Pada hasil keluaran, hanya Vertex 0 dan Vertex 1 yang akan menampilkan informasi data jalur (1,w=5) dan (0,w=5), sementara simpul lainnya (2 sampai 7) akan terlihat kosong karena belum memiliki tetangga.



D. Implementasi Dijkstra

Deskripsi: 
Program ini menerapkan algoritma Dijkstra secara mandiri untuk mencari jalur terpendek dari vertex 0 ke vertex lain dalam graf berbobot yang telah ditentukan.

Syntax Program:


Output:

Penjelasan code:
#include <iostream>
#include <vector>
#include <queue>
#include <climits>

using namespace std;

typedef pair<int, int> pii;
  • #include <climits>: Pustaka ini disertakan untuk menggunakan konstanta INT_MAX, yang merepresentasikan nilai integer tertinggi yang dimungkinkan (berfungsi sebagai nilai tak hingga atau infinity).

  • typedef pair<int, int> pii;: Membuat alias pii untuk mempersingkat penulisan pair<int, int>. Dalam algoritma Dijkstra, komponen pair ini digunakan secara fleksibel untuk menyimpan pasangan data {bobot, simpul} atau {simpul, bobot}.


struct WeightedGraph {
    int V;
    vector<vector<pii>> adj;
    WeightedGraph(int V) : V(V), adj(V) {}
    void addEdge(int u, int v, int w) { adj[u].push_back({v, w}); adj[v].push_back({u, w}); }
  • struct WeightedGraph: Berbeda dengan class yang bersifat private secara bawaan, anggota di dalam struct secara otomatis bersifat public.

  • WeightedGraph(int V) : V(V), adj(V) {}: Constructor yang langsung memesan ukuran vektor luar adj sebanyak V elemen.

  • void addEdge(int u, int v, int w): Fungsi untuk menambahkan jalur tidak berarah (undirected edge) antara simpul u dan v dengan bobot w ke dalam Adjacency List.


    void Dijkstra(int start) {
        vector<int> dist(V, INT_MAX);
        priority_queue<pii, vector<pii>, greater<pii>> pq;
        dist[start] = 0; pq.push({0, start});
  • vector<int> dist(V, INT_MAX);: Membuat vektor penampung jarak dist berukuran V. Semua simpul diinisialisasi dengan jarak INT_MAX (tak hingga) karena di awal belum ada jalur yang diketahui.

  • priority_queue<pii, vector<pii>, greater<pii>> pq;: Membuat antrean prioritas yang dikonfigurasi sebagai Min-Heap. Artinya, data dengan nilai terkecil (dalam hal ini, jarak terpendek) akan selalu diposisikan di paling atas untuk diproses terlebih dahulu.

  • Inisialisasi: Jarak dari simpul asal (start) ke dirinya sendiri diatur sebesar 0, lalu dimasukkan ke dalam antrean pq dalam format {jarak, simpul} yaitu {0, start}.


        while(!pq.empty()) {
            int d = pq.top().first, u = pq.top().second; pq.pop();
            if(d > dist[u]) continue;
            for(auto& edge : adj[u]) {
                if(dist[u] + edge.second < dist[edge.first]) {
                    dist[edge.first] = dist[u] + edge.second;
                    pq.push({dist[edge.first], edge.first});
                }
            }
        }
  • while(!pq.empty()): Perulangan utama algoritma yang berjalan selama masih ada simpul di dalam antrean untuk dieksplorasi.

  • pq.top() dan pq.pop(): Mengambil simpul u yang memiliki estimasi jarak d terkecil saat itu, lalu mengeluarkannya dari antrean.

  • if(d > dist[u]) continue;: Langkah optimasi. Jika jarak d yang diambil dari antrean ternyata lebih besar dari jarak terbaik yang sudah tercatat di vektor dist[u], maka proses untuk simpul ini dilewati karena sudah usang.

  • Relaksasi Jalur (Relaxation): Program memeriksa semua tetangga (edge.first) dari simpul u. Jika jarak menuju tetangga tersebut melalui simpul u ternyata lebih pendek dari jarak yang tercatat sebelumnya (dist[u] + edge.second < dist[edge.first]), maka data di dalam tabel dist diperbarui dan data barunya dimasukkan ke dalam antrean pq.


        for(int i=0; i<V; ++i) cout << "Jarak terpendek ke " << i << ": " << dist[i] << endl;
    }
};
  • Mencetak Hasil: Setelah semua simpul selesai dieksplorasi dan antrean kosong, perulangan ini mencetak total jarak terpendek dari simpul asal ke setiap simpul indeks 0 hingga V - 1.


int main() {
    WeightedGraph wg(8);
    wg.addEdge(0, 1, 4); wg.addEdge(0, 2, 1);
    wg.Dijkstra(0);
    return 0;
}
  • WeightedGraph wg(8);: Membuat objek graf berbobot bernama wg dengan kapasitas total 8 simpul (indeks 0 sampai 7).

  • wg.addEdge(...): Membuat dua jalur: menghubungkan simpul 0 dengan 1 (bobot 4) dan simpul 0 dengan 2 (bobot 1).

  • wg.Dijkstra(0);: Menjalankan algoritma Dijkstra dimulai dari simpul 0. Hasil keluarannya akan menampilkan jarak ke simpul 0 adalah 0, ke simpul 1 adalah 4, ke simpul 2 adalah 1, sedangkan simpul sisanya (3 sampai 7) akan bernilai 2147483647 (nilai asli INT_MAX) karena tidak terhubung ke simpul 0.


E. Simulasi Jaringan Sosial

Deskripsi: 
Program ini mensimulasikan hubungan sosial antar individu menggunakan map dan vector untuk mempermudah identifikasi pertemanan berbasis nama string dibandingkan indeks angka.

Syntax Program:


Output:

Penjelasan code:
#include <iostream>
#include <vector>
#include <map>
#include <string>

using namespace std;
  • #include <map> dan #include <string>: Pustaka tambahan yang digunakan dalam program ini. <map> digunakan untuk menyimpan hubungan berpasangan (key-value), sedangkan <string> digunakan untuk memproses tipe data teks (nama orang).

  • using namespace std;: Digunakan agar kita tidak perlu menuliskan std:: secara berulang sebelum perintah seperti cout, map, vector, atau string.


class SocialNetwork {
    map<string, vector<string>> network;
public:
  • class SocialNetwork: Membuat sebuah kelas bernama SocialNetwork untuk membungkus seluruh data dan fungsi jaringan pertemanan.

  • map<string, vector<string>> network: Struktur data utama berupa Adjacency List.

    • string bertindak sebagai kunci (key) untuk menyimpan nama orang (misal: "Andi").

    • vector<string> bertindak sebagai nilai (value) untuk menyimpan daftar nama teman-teman dari orang tersebut.

    • Keunggulan menggunakan std::map di sini adalah kita tidak memerlukan indeks angka (seperti 0, 1, 2) untuk mewakili seseorang; kita bisa langsung menggunakan nama mereka sebagai pengenal.


    void addFriendship(string p1, string p2) {
        network[p1].push_back(p2);
        network[p2].push_back(p1);
    }
  • void addFriendship(string p1, string p2): Fungsi untuk membuat hubungan pertemanan antara p1 (orang pertama) dan p2 (orang kedua).

  • Mekanisme Kerja: Nama p2 dimasukkan ke dalam daftar teman p1, dan nama p1 dimasukkan ke dalam daftar teman p2. Karena hubungan ini dicatat secara timbal balik, kode ini membentuk Undirected Graph (Graf Tidak Berarah).

  • Catatan: Jika nama p1 atau p2 belum pernah terdaftar sebelumnya di dalam map, C++ akan otomatis membuatkan kunci baru untuk nama tersebut secara dinamis.


    void showNetwork() {
        for(auto const& [person, friends] : network) {
            cout << person << " berteman dengan: ";
            for(auto const& f : friends) cout << f << " ";
            cout << endl;
        }
    }
};
  • void showNetwork(): Fungsi untuk menampilkan seluruh jaringan pertemanan ke layar komputer.

  • for(auto const& [person, friends] : network): Menggunakan fitur modern Structured Binding (C++17) untuk memecah isi map secara langsung. Variabel person mengambil data nama (kunci), dan variabel friends mengambil daftar teman (nilai).

  • Sifat std::map: Karena menggunakan std::map, data nama orang (person) otomatis akan diurutkan secara alfabetis (A-Z) saat dicetak oleh perulangan luar.

  • Perulangan Dalam: Berjalan menyusuri vektor friends milik orang yang bersangkutan untuk mencetak nama teman-temannya satu per satu dipisahkan oleh spasi.


int main() {
    SocialNetwork sn;
    sn.addFriendship("Andi", "Budi");
    sn.addFriendship("Budi", "Citra");
    sn.showNetwork();
    return 0;
}
  • SocialNetwork sn;: Membuat objek jaringan pertemanan baru bernama sn.

  • Membangun Hubungan:

    • Andi berteman dengan Budi (Andi --> Budi).

    • Budi berteman dengan Citra (Budi --> Citra).

  • sn.showNetwork(): Memanggil fungsi cetak. Hasil akhir di layar akan menunjukkan daftar pertemanan yang terurut rapi: Andi berteman dengan Budi; Budi berteman dengan Andi dan Citra; Citra berteman dengan Budi.


Postingan populer dari blog ini

Curiculum Vitae - Aga Nafta Filadelfiano

Struktur Data - Studi Kasus Stack

Struktur Data - Tipe Data & Array