Struktur Data - Graf
Kelas : Struktur Data (D)
Graf
1. Implementasi Adjacency Matrix
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.
class Graph {
private:
int mat[100][100];
int ver;
class Graph: Membuat sebuah kelas bernamaGraphuntuk 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. Parametervmenentukan jumlah simpul.Nested Loop (
for): Digunakan untuk melakukan inisialisasi awal. Semua elemen di dalam matriks diisi dengan angka0, 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 simpuludan simpulv.mat[u][v] = 1danmat[v][u] = 1: Mengubah nilai matriks pada koordinat tersebut menjadi1(menandakan ada hubungan). Karena kedua arah diisi, program ini merepresentasikan Undirected Graph (Graf Tidak Berarah), di mana jikauterhubung kev, makavotomatis terhubung keu.
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
0hinggaver - 1untuk 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 bernamagdengan 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
class gh {
private:
int v;
vector<vector<int>> adj;
class gh: Membuat kelas bernamagh(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 parameterversebagai jumlah simpulnya.adj.resize(v): Mengubah ukuran vektor luaradjagar pas menampung sebanyakvelemen. 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 simpuludan simpulv.push_back(): Memasukkan simpulvke dalam daftar tetangga miliku, dan sebaliknya memasukkanuke daftar tetanggav. Karena saling mencatat, program ini merepresentasikan Undirected Graph (Graf Tidak Berarah).Catatan: Nama parameter
vdi fungsi ini menimpa (shadowing) variabelvmilik 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 indeks0hinggav - 1untuk mencetak nomor simpul utama (misal:0 ->).Range-based For Loop (
for(int n : adj[i])): Fitur modern C++ untuk menyusuri dan mencetak setiap simpul tetangganyang terdaftar di dalamadj[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 grafgdengan 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
class gh {
private:
int v;
vector<vector<int>> adj;
vector<bool> vis;
class gh: Membuat kelas bernamaghuntuk merepresentasikan graf beserta struktur data pendukung jalannya algoritma DFS.int vdanvector<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 bernilaitrueartinya simpul sudah dikunjungi, danfalsejika 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 kunjunganvissebanyakvelemen, sekaligus mengisi seluruh nilai awalnya denganfalsekarena 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 simpuludan simpulvsecara 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 simpulvyang 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 simpulv. Jika ditemukan tetangga yang belum dikunjungi (if(!vis[u])), program langsung melompat masuk ke tetangga tersebut dengan memanggil kembali fungsidfs(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 bernamagdengan 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 simpul0. Hasil urutan penjelajahan yang akan dicetak oleh kode ini adalah:0 1 3 2 4.
4. Implementasi BFS
class Graph {
private:
int V;
vector<vector<int>> adj;
class Graph: Membuat kelas bernamaGraphuntuk 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) vektoradjsesuai jumlah simpul tersebut.void addEdge(int u,int v): Fungsi untuk menambahkan jalur tidak berarah (undirected edge) antara simpuludanv. Karena tidak berarah, kedua simpul saling dimasukkan ke dalam daftar tetangga masing-masing menggunakanpush_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 berukuranVdengan nilai awalfalseuntuk 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 antreanq.
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()danq.pop(): Mengambil simpul di barisan terdepan antrean (disimpan di variabelv), 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 simpulv. Jika tetangga tersebut belum pernah dikunjungi (!visited[u]), maka statusnya diubah menjaditruedan dimasukkan ke dalam antreanquntuk 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 bernamagdengan 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 simpul0. 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
class gh {
private:
map<char, vector<pair<char, int>>> adj;
class gh: Membuat kelas bernamagh(singkatan dari graph) untuk merepresentasikan graf berbobot.map<char, vector<pair<char, int>>> adj: Struktur data utama berupa Adjacency List.charbertindak 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 dalampair, 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 parameterver(jumlah simpul) tidak digunakan di dalam fungsi. Hal ini karena penggunaanstd::mapmemungkinkan 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 simpuludanvdengan bobotw.push_back({v, w}): Menggunakan tanda kurung kurawal{}untuk membuatpairsecara langsung (initializer list). Jalur ini didaftarkan secara timbal balik (dariukevdan darivkeu), 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 isimapsecara langsung: variabelvertexmengambil data kunci (key / nama simpul) dan variabeledgesmengambil data nilai (value / daftar tetangga). Karenastd::mapotomatis mengurutkan kuncinya, simpul akan tercetak urut abjad (A, B, C, D).edge.firstdanedge.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 grafg(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
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 bernamadistberukuranV(jumlah simpul) dan mengisi seluruh nilai awalnya denganINF.priority_queue<... greater<...>> pq;: Membuat sebuah antrean prioritas (Min-Heap). Konfigurasigreatermemastikan bahwa elemen dengan bobot/jarak terkecil akan selalu berada di urutan paling atas (top) untuk diproses duluan.Inisialisasi: Jarak ke simpul asal (
start) diatur menjadi0(dist[start] = 0), lalu dimasukkan ke dalam antreanpqdengan 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
vdari simpulu. Jika ditemukan jalur baru yang lebih pendek melalui rumus dist[v] > dist[u] + w, maka jarak di tabeldist[v]akan diperbarui dengan nilai yang lebih kecil tersebut, lalu dimasukkan ke dalam antreanpquntuk 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:0untuk Surabaya,1untuk Sidoarjo, dan2untuk 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 indeks0(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
class Graph {
private:
int v;
vector<vector<int>> adj;
vector<string> users;
class Graph: Membuat kelas bernamaGraphuntuk 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 luaradjagar 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 indeksudan pengguna di indeksv_idx.push_back(): Pertemanan ini bersifat timbal balik (Undirected Graph). Jikauberteman denganv_idx, maka otomatisv_idxjuga berteman denganu, 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 menggunakanusers[i].Range-based For Loop (
for neighbor : adj[i]): Mengambil setiap indeks teman (neighbor) yang terdaftar di dalamadj[i], lalu langsung mencetak nama asli dari teman tersebut melalui perintahusers[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, dan4: Eko.Graph g(5, names): Membuat objek grafgyang 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
#include <iostream>
#include <vector>
using namespace std;
#include <iostream>: Pustaka standar C++ yang digunakan untuk operasi input dan output data (seperti perintahcoutdanendl).#include <vector>: Pustaka standar untuk menggunakan kontainerstd::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 awalanstd::di depan setiap perintah.
class Graph {
int V;
vector<vector<int>> adj;
class Graph: Mendefinisikan sebuah kelas bernamaGraphuntuk 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 kelasVdengan nilai dari parameterVyang diterima.adj(V): Langsung mengubah ukuran awal (resize) vektor luaradjagar berukuran sebanyakVelemen, 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 simpuludan simpulv.push_back(): Memasukkan simpulvke dalam daftar miliku, dan sebaliknya memasukkanuke dalam daftar milikv. 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 indeks0hinggaV - 1.Range-based For Loop (
for(int v : adj[i])): Mengambil setiap nilai simpul tetanggavyang tersimpan di dalam daftaradj[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 grafgdengan 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
#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 vektoradjsebanyakVelemen.void addEdge(int u, int v): Fungsi untuk mendaftarkan hubungan bertetangga antara simpuludanv. 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 ditandaivisited = 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 ditandaivisited = truedan 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 ditandaitruedan 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 bernamagdengan 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
#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 bernamapiiuntuk menyingkat penulisanpair<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 denganclass, secara default seluruh isi (variabel dan fungsi) di dalamstructbersifat 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 tipepii(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 variabelVsekaligus langsung memesan ukuran awal vektoradjsebanyakVelemen.
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 simpuludan simpulvdengan bobot sebesarw.push_back({v, w}): Membuat objekpairsecara instan menggunakan kurung kurawal{}lalu memasukkannya ke dalam list. Karena jalur ini dicatat secara timbal balik (di list milikumaupun milikv), 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 indeks0hinggaV - 1.Range-based For Loop (
for(auto& edge : adj[i])): Berjalan membaca setiap pair jalur yang terhubung pada simpulisecara referensi (&) agar lebih cepat dan hemat memori.edge.firstdanedge.second:edge.firstdigunakan untuk mengambil nomor simpul tetangga, sedangkanedge.seconddigunakan 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 bernamawgdengan total alokasi 8 simpul (indeks 0 sampai 7).wg.addEdge(0, 1, 5): Menghubungkan simpul0dengan simpul1dan memberikan bobot jalur sebesar5.wg.print(): Memanggil fungsi untuk mencetak struktur graf. Pada hasil keluaran, hanyaVertex 0danVertex 1yang 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
#include <iostream>
#include <vector>
#include <queue>
#include <climits>
using namespace std;
typedef pair<int, int> pii;
#include <climits>: Pustaka ini disertakan untuk menggunakan konstantaINT_MAX, yang merepresentasikan nilai integer tertinggi yang dimungkinkan (berfungsi sebagai nilai tak hingga atau infinity).typedef pair<int, int> pii;: Membuat aliaspiiuntuk mempersingkat penulisanpair<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 denganclassyang bersifat private secara bawaan, anggota di dalamstructsecara otomatis bersifat public.WeightedGraph(int V) : V(V), adj(V) {}: Constructor yang langsung memesan ukuran vektor luaradjsebanyakVelemen.void addEdge(int u, int v, int w): Fungsi untuk menambahkan jalur tidak berarah (undirected edge) antara simpuludanvdengan bobotwke 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 jarakdistberukuranV. Semua simpul diinisialisasi dengan jarakINT_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 sebesar0, lalu dimasukkan ke dalam antreanpqdalam 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()danpq.pop(): Mengambil simpuluyang memiliki estimasi jarakdterkecil saat itu, lalu mengeluarkannya dari antrean.if(d > dist[u]) continue;: Langkah optimasi. Jika jarakdyang diambil dari antrean ternyata lebih besar dari jarak terbaik yang sudah tercatat di vektordist[u], maka proses untuk simpul ini dilewati karena sudah usang.Relaksasi Jalur (
Relaxation): Program memeriksa semua tetangga (edge.first) dari simpulu. Jika jarak menuju tetangga tersebut melalui simpuluternyata lebih pendek dari jarak yang tercatat sebelumnya (dist[u] + edge.second < dist[edge.first]), maka data di dalam tabeldistdiperbarui dan data barunya dimasukkan ke dalam antreanpq.
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
0hinggaV - 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 bernamawgdengan 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 simpul0. 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 bernilai2147483647(nilai asliINT_MAX) karena tidak terhubung ke simpul 0.
E. Simulasi Jaringan Sosial
#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 menuliskanstd::secara berulang sebelum perintah seperticout,map,vector, ataustring.
class SocialNetwork {
map<string, vector<string>> network;
public:
class SocialNetwork: Membuat sebuah kelas bernamaSocialNetworkuntuk membungkus seluruh data dan fungsi jaringan pertemanan.map<string, vector<string>> network: Struktur data utama berupa Adjacency List.stringbertindak 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::mapdi 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 antarap1(orang pertama) danp2(orang kedua).Mekanisme Kerja: Nama
p2dimasukkan ke dalam daftar temanp1, dan namap1dimasukkan ke dalam daftar temanp2. Karena hubungan ini dicatat secara timbal balik, kode ini membentuk Undirected Graph (Graf Tidak Berarah).Catatan: Jika nama
p1ataup2belum pernah terdaftar sebelumnya di dalammap, 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 isimapsecara langsung. Variabelpersonmengambil data nama (kunci), dan variabelfriendsmengambil daftar teman (nilai).Sifat
std::map: Karena menggunakanstd::map, data nama orang (person) otomatis akan diurutkan secara alfabetis (A-Z) saat dicetak oleh perulangan luar.Perulangan Dalam: Berjalan menyusuri vektor
friendsmilik 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 bernamasn.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.