cv.cm

Pemrograman · Algoritme

Penjelasan Breadth-First Search (BFS): cara kerja, kode, dan kompleksitas

5 menit baca

Jawaban singkat

Breadth-first search (BFS) adalah penelusuran graf yang mengunjungi node awal lebih dulu, lalu semua tetangganya, lalu tetangga dari tetangga itu, dan seterusnya, satu level demi satu level. BFS memakai queue first-in, first-out dan sebuah himpunan node yang sudah dikunjungi. Pada graf tak berbobot, BFS menemukan jalur terpendek (jumlah edge paling sedikit) dari node awal ke setiap node yang dapat dijangkau. Waktu jalannya O(V + E).

Masalah yang diselesaikan BFS

Banyak masalah ternyata adalah graf: halaman web dan tautannya, teman dalam jejaring sosial, kotak pada papan permainan, keadaan sebuah puzzle. BFS menjawab dua pertanyaan umum pada graf semacam itu: node mana saja yang bisa dicapai dari node awal, dan berapa jumlah langkah paling sedikit untuk mencapai masing-masing node?

Karena BFS menjelajah dalam lingkaran berjarak makin jauh, saat pertama kali mencapai suatu node ia selalu lewat jalur dengan edge paling sedikit. Inilah yang menjadikan BFS algoritma standar untuk jalur terpendek ketika setiap edge berbiaya sama.

Ide dasar dengan kata-kata sederhana

  1. Masukkan node awal ke dalam queue dan tandai sebagai sudah dikunjungi.
  2. Ambil node di depan queue.
  3. Untuk setiap tetangga yang belum dikunjungi, tandai sebagai sudah dikunjungi dan tambahkan ke belakang queue.
  4. Ulangi langkah 2 dan 3 sampai queue kosong.

Tandai node sebagai sudah dikunjungi saat memasukkannya ke queue, bukan saat mengambilnya. Kalau tidak, node yang sama bisa ditambahkan berkali-kali sebelum diproses.

Contoh langkah demi langkah

Ambil graf tak berarah ini: A–B, A–C, B–D, C–D, C–E, D–F. Mulai dari A dan kunjungi tetangga sesuai urutan abjad.

LangkahDiambil dari queueBaru ditemukanQueue setelah langkah
0—A (jarak 0)A
1AB, C (jarak 1)B, C
2BD (jarak 2)C, D
3CE (jarak 2)D, E
4DF (jarak 3)E, F
5Etidak adaF
6Ftidak adakosong

Urutan kunjungannya adalah A, B, C, D, E, F. D bisa dicapai dari B maupun C, tetapi hanya ditemukan sekali, dari B, karena pada saat itu D sudah ditandai sebagai dikunjungi.

Implementasi Python

Gunakan collections.deque sebagai queue: popleft() berkompleksitas O(1), sedangkan list.pop(0) O(n). Graf direpresentasikan sebagai dictionary yang memetakan setiap node ke list tetangganya (adjacency list).

from collections import deque
def bfs(graph, start):
    """Return the distance (number of edges) from start to each reachable node."""
    dist = {start: 0}
    queue = deque([start])
    while queue:
        node = queue.popleft()
        for nxt in graph[node]:
            if nxt not in dist:          # not visited yet
                dist[nxt] = dist[node] + 1
                queue.append(nxt)
    return dist
graph = {
    "A": ["B", "C"], "B": ["A", "D"], "C": ["A", "D", "E"],
    "D": ["B", "C", "F"], "E": ["C"], "F": ["D"],
}
print(bfs(graph, "A"))  # {'A': 0, 'B': 1, 'C': 1, 'D': 2, 'E': 2, 'F': 3}

Di sini dictionary dist punya dua fungsi: sebagai himpunan node yang dikunjungi sekaligus penyimpan jawaban. Untuk merekonstruksi jalurnya, simpan juga parent dari setiap node lalu telusuri mundur dari target.

def shortest_path(graph, start, goal):
    parent = {start: None}
    queue = deque([start])
    while queue:
        node = queue.popleft()
        if node == goal:
            path = []
            while node is not None:
                path.append(node)
                node = parent[node]
            return path[::-1]
        for nxt in graph[node]:
            if nxt not in parent:
                parent[nxt] = node
                queue.append(nxt)
    return None  # goal not reachable
print(shortest_path(graph, "A", "F"))  # ['A', 'B', 'D', 'F']

Time and space complexity

UkuranBiayaAlasan
WaktuO(V + E)Setiap node dimasukkan ke queue sekali dan setiap edge diperiksa sekali (dua kali pada graf tak berarah).
RuangO(V)Himpunan visited, queue, dan peta parent masing-masing berisi paling banyak V entri.
Grid dengan R × C selO(R × C)Setiap sel adalah sebuah node dengan paling banyak 4 edge.

V adalah jumlah vertex (node) dan E jumlah edge. Dengan adjacency matrix alih-alih list, waktunya menjadi O(V²) karena mencari tetangga sebuah node membutuhkan O(V).

Varian dan kesalahan umum

  • BFS pada grid: anggap setiap sel sebagai node dan empat (atau delapan) sel di sekitarnya sebagai edge. Periksa batas dan dinding sebelum menambahkan sel.
  • BFS multi-sumber: masukkan beberapa node awal ke queue dengan jarak 0. Hasilnya adalah jarak ke sumber terdekat, misalnya pintu keluar terdekat dalam labirin.
  • BFS 0-1: jika bobot edge hanya 0 atau 1, gunakan deque dan dorong tetangga berbobot 0 ke depan. Hasilnya jalur terpendek dalam O(V + E).
  • BFS dua arah: cari dari node awal dan dari tujuan secara bersamaan, lalu berhenti saat kedua frontier bertemu. Cara ini sering menjelajah jauh lebih sedikit node.
  • Pemrosesan per level: catat len(queue) di awal setiap putaran dan ambil tepat sebanyak itu node untuk menangani satu level sekaligus.

Kapan memakai BFS dan penggunaannya di dunia nyata

SituasiPilihan terbaik
Jalur terpendek, semua edge berbiaya samaBFS
Jalur terpendek, bobot non-negatifAlgoritma Dijkstra
Jalur terpendek dengan estimasi jarak yang baikA* search
Deteksi siklus, urutan topologis, komponen terhubungDFS (BFS juga bisa untuk komponen)
Graf sangat dalam dengan memori terbatasDFS atau iterative deepening
  • Soal wawancara: jalur terpendek dalam labirin atau grid, word ladder, rotting oranges (BFS multi-sumber), penelusuran level-order pohon biner, jumlah langkah minimum kuda catur.
  • Jaringan: mencari semua perangkat dalam k hop, broadcast di jaringan peer-to-peer, "orang yang mungkin Anda kenal" pada jarak 2 di graf sosial.
  • Web crawler yang mengunjungi halaman berdasarkan jarak tautan dari halaman awal.
  • Garbage collector (misalnya copying collector Cheney) dan pemecah puzzle yang membutuhkan langkah paling sedikit.

FAQ

Struktur data apa yang dipakai BFS?

BFS memakai queue FIFO untuk menentukan node berikutnya yang diproses dan sebuah set (atau dictionary) untuk mengingat node yang sudah dikunjungi. Di Python, gunakan collections.deque untuk queue.

Apakah BFS selalu menemukan jalur terpendek?

Ya, pada graf tak berbobot atau ketika setiap edge berbobot sama, BFS menemukan jalur dengan edge paling sedikit. Pada graf berbobot tidak demikian; gunakan algoritma Dijkstra atau Bellman-Ford.

Apa perbedaan BFS dan DFS?

BFS menjelajah level demi level dengan queue, sehingga menemukan jalur terpendek pada graf tak berbobot. DFS masuk sedalam mungkin lebih dulu dengan stack atau rekursi, cocok untuk deteksi siklus, topological sort, dan pencarian menyeluruh.

Mengapa BFS saya lambat di Python?

Penyebab yang paling umum adalah list.pop(0), yang menggeser seluruh list di setiap pemanggilan, dan memeriksa node yang dikunjungi memakai list alih-alih set. Gunakan deque.popleft() dan set atau dictionary.

Bisakah BFS dipakai pada pohon?

Bisa. Pada pohon, BFS adalah penelusuran level-order. Pohon tidak punya siklus, sehingga set visited bisa dilewati jika Anda hanya bergerak dari parent ke child.

Semua tutorial pemrograman