Breadth-First Search (BFS)
Terakhir diperbarui
Breadth-first search adalah algoritma yang menjelajahi graf level demi level. Dimulai dari sebuah node sumber, BFS mengunjungi semua tetangga langsungnya terlebih dahulu, lalu semua tetangga mereka yang belum dikunjungi, dan seterusnya, meluas ke luar dalam lingkaran-lingkaran dengan jarak yang makin jauh. Tekan Putar di atas untuk melihatnya menyebar dari node awal, satu lapis demi satu lapis.
BFS memakai queue first-in-first-out, dan queue inilah yang memaksakan urutan level demi level. Karena BFS mencapai node sesuai urutan jumlah lompatan, BFS menemukan jalur terpendek (edge paling sedikit) pada graf tak berbobot. BFS mengunjungi setiap node dan edge sekali, jadi berjalan dalam waktu O(V + E).
Kompleksitas waktu dan ruang
| Ukuran | Kompleksitas | Catatan |
|---|---|---|
| Waktu | O(V + E) | Setiap vertex dan edge dikunjungi sekali |
| Ruang | O(V) | Queue + himpunan visited, kasus terburuk semua node |
| Penelusuran | Level demi level | Node terdekat lebih dulu, dalam lingkaran |
| Jalur terpendek | Ya (tak berbobot) | Mencapai setiap node lewat edge paling sedikit |
Langkah demi langkah
| Langkah | Apa yang terjadi |
|---|---|
| 1 | Masukkan node sumber ke queue (enqueue). |
| 2 | Keluarkan node terdepan (dequeue) dan tandai sudah dikunjungi. |
| 3 | Periksa setiap tetangganya. |
| 4 | Masukkan ke queue setiap tetangga yang belum dikunjungi atau belum ada di queue. |
| 5 | Ulangi sampai queue kosong. |
Contoh penerapan
Menelusuri graf ini dari node 0, dengan edge 0-1, 0-2, 1-3, 2-3, 2-4:
| Langkah | Sudah dikunjungi | Queue (frontier) |
|---|---|---|
| Mulai | {} | [0] |
Dequeue 0 | {0} | [1, 2] |
Dequeue 1 | {0, 1} | [2, 3] |
Dequeue 2 | {0, 1, 2} | [3, 4] |
Dequeue 3 | {0, 1, 2, 3} | [4] |
Dequeue 4 | {0, 1, 2, 3, 4} | [] (selesai) |
Kapan memakai BFS
| Pakai saat | Hindari saat |
|---|---|
| Kamu butuh jalur terpendek pada graf tak berbobot | Edge punya bobot: pakai Dijkstra |
| Target kemungkinan besar dekat dengan sumber | Grafnya sangat lebar: queue bisa menampung frontier yang sangat besar |
| Kamu ingin menjelajahi graf berdasarkan urutan level | Kamu hanya perlu mencapai node mana pun, dan DFS memakai lebih sedikit memori |
| Kamu mencari komponen terhubung atau rute dengan lompatan paling sedikit | Kamu butuh topological sort atau deteksi siklus: DFS lebih cocok |
BFS vs DFS
Keduanya menelusuri setiap node dalam O(V + E), tetapi urutan dan struktur datanya berbeda. Lihat visualisasi depth-first search untuk membandingkan keduanya berdampingan.
| Aspek | BFS | DFS |
|---|---|---|
| Struktur data | Queue (FIFO) | Stack / rekursi |
| Urutan | Level demi level (terdekat lebih dulu) | Masuk dalam di satu cabang, lalu backtrack |
| Jalur terpendek (tak berbobot) | Ya: edge paling sedikit | Tidak: tidak terjamin |
| Memori pada graf lebar | Tinggi: frontier bisa sangat besar | Rendah: satu jalur dalam satu waktu |
| Paling cocok untuk | Lompatan terpendek, komponen terhubung | Deteksi siklus, topological sort, backtracking |
Kode Breadth-First Search
Implementasi Breadth-First Search yang rapi dan siap dijalankan dalam Python, JavaScript, Java, C++, C. Pilih bahasa, salin kodenya, atau buka langsung di Coddy Playground.
Kode Breadth-First Search dalam Python
1from collections import deque2
3
4def bfs(graph, start):5 visited = {start}6 queue = deque([start])7 order = []8 while queue:9 node = queue.popleft()10 order.append(node)11 for neighbor in graph[node]:12 if neighbor not in visited:13 visited.add(neighbor) # mark on enqueue, not dequeue14 queue.append(neighbor)15 return order16
17
18graph = {19 "A": ["B", "C"],20 "B": ["D", "E"],21 "C": ["F"],22 "D": [],23 "E": ["F"],24 "F": [],25}26
27print("BFS order:", " -> ".join(bfs(graph, "A")))Kode Breadth-First Search dalam JavaScript
1const graph = {2 A: ["B", "C"],3 B: ["D", "E"],4 C: ["F"],5 D: [],6 E: ["F"],7 F: [],8};9
10function bfs(start) {11 const visited = new Set([start]);12 const queue = [start];13 const order = [];14 while (queue.length > 0) {15 const node = queue.shift(); // Dequeue the oldest node16 order.push(node);17 for (const next of graph[node]) {18 if (!visited.has(next)) {19 visited.add(next);20 queue.push(next);21 }22 }23 }24 return order;25}26
27console.log("BFS from A:", bfs("A").join(" -> "));Kode Breadth-First Search dalam Java
1import java.util.ArrayDeque;2import java.util.List;3import java.util.Queue;4
5public class Main {6 public static void main(String[] args) {7 List<List<Integer>> adj = List.of(8 List.of(1, 2), // neighbors of 09 List.of(0, 3, 4), // neighbors of 110 List.of(0, 5),11 List.of(1),12 List.of(1, 5),13 List.of(2, 4)14 );15 boolean[] visited = new boolean[adj.size()];16 Queue<Integer> queue = new ArrayDeque<>();17 visited[0] = true;18 queue.add(0);19
20 StringBuilder order = new StringBuilder("BFS from 0:");21 while (!queue.isEmpty()) {22 int node = queue.poll();23 order.append(" ").append(node);24 // Mark neighbors when enqueued so nothing enters twice25 for (int next : adj.get(node)) {26 if (!visited[next]) {27 visited[next] = true;28 queue.add(next);29 }30 }31 }32 System.out.println(order);33 }34}Kode Breadth-First Search dalam C++
1#include <iostream>2#include <queue>3#include <vector>4
5void bfs(int start, const std::vector<std::vector<int>>& adj) {6 std::vector<bool> visited(adj.size(), false);7 std::queue<int> frontier;8 visited[start] = true;9 frontier.push(start);10 // Visit nodes level by level11 while (!frontier.empty()) {12 int node = frontier.front();13 frontier.pop();14 std::cout << node << " ";15 for (int next : adj[node]) {16 if (!visited[next]) {17 visited[next] = true;18 frontier.push(next);19 }20 }21 }22}23
24int main() {25 // 6-node undirected graph as an adjacency list26 std::vector<std::vector<int>> adj = {27 {1, 2}, // 028 {0, 3, 4}, // 129 {0, 5}, // 230 {1}, // 331 {1, 5}, // 432 {2, 4}, // 533 };34 std::cout << "BFS from node 0: ";35 bfs(0, adj);36 std::cout << "\n";37 return 0;38}Kode Breadth-First Search dalam C
1#include <stdbool.h>2#include <stdio.h>3
4#define N 65
6void bfs(int start, const int adj[N][N]) {7 bool visited[N] = {false};8 int queue[N]; // fixed-size queue: head chases tail9 int head = 0, tail = 0;10 visited[start] = true;11 queue[tail++] = start;12 // Visit nodes level by level13 while (head < tail) {14 int node = queue[head++];15 printf("%d ", node);16 for (int next = 0; next < N; next++) {17 if (adj[node][next] && !visited[next]) {18 visited[next] = true;19 queue[tail++] = next;20 }21 }22 }23}24
25int main(void) {26 // 6-node undirected graph as an adjacency matrix27 int adj[N][N] = {28 {0, 1, 1, 0, 0, 0},29 {1, 0, 0, 1, 1, 0},30 {1, 0, 0, 0, 0, 1},31 {0, 1, 0, 0, 0, 0},32 {0, 1, 0, 0, 0, 1},33 {0, 0, 1, 0, 1, 0},34 };35 printf("BFS from node 0: ");36 bfs(0, adj);37 printf("\n");38 return 0;39}FAQ Breadth-First Search
Berapa kompleksitas waktu BFS?
O(V + E), dengan V adalah jumlah vertex dan E jumlah edge, karena BFS mengunjungi setiap vertex sekali dan memeriksa setiap edge sekali. BFS memakai ruang O(V) untuk queue dan himpunan visited.Apakah BFS menemukan jalur terpendek?
Apa perbedaan BFS dan DFS?
Kapan sebaiknya memakai BFS, bukan algoritma Dijkstra?
O(V + E) tanpa priority queue. Algoritma Dijkstra dibutuhkan saat edge punya bobot yang berbeda-beda; menjalankan BFS biasa pada graf berbobot memberi jalur dengan lompatan paling sedikit, bukan jalur dengan biaya paling rendah.Mengapa BFS butuh himpunan visited?
Graf bisa berisi siklus, jadi tanpa himpunan visited BFS akan memasukkan node yang sama ke queue berulang kali dan berputar tanpa akhir. Menandai node saat pertama kali dimasukkan ke queue (bukan saat dikeluarkan) juga mencegah node yang sama ditambahkan ke queue dua kali oleh tetangga yang berbeda.
Sebaiknya node ditandai sudah dikunjungi saat enqueue atau saat dequeue?
Tandai saat enqueue. Jika kamu menunggu sampai dequeue, sebuah node bisa ditambahkan ke queue beberapa kali oleh tetangga yang berbeda sebelum diproses, sehingga membuang memori dan waktu. Menandai saat enqueue menjamin setiap node masuk ke queue tepat satu kali.