Genişlik Öncelikli Arama Breadth-First Search (BFS)

BFS nedir, kuyruk ile gerçekleme, seviye seviye dolaşma, ağırlıksız grafta en kısa yol bulma — adım adım görseller, karmaşıklık analizi ve C kodu.

🗂️ Veri Yapıları 📅 22 February 2026 👁️ 14 görüntülenme

BFS Nedir?

Genişlik Öncelikli Arama (BFS), bir grafı seviye seviye (katman katman) dolaşan algoritmadır. Başlangıç düğümünden başlar ve önce tüm 1-mesafe komşuları, sonra 2-mesafe komşuları, sonra 3-mesafe komşuları... şeklinde ilerler. Su yüzeyine atılan taşın yarattığı dalgalar gibi düşünülebilir — merkezdeki taş başlangıç düğümü, her dalga halkası bir seviyedir.

BFS — Genişlik Öncelikli

Önce yakın komşuları keşfet, sonra uzaklara ilerle.
Veri yapısı: Kuyruk (Queue) — FIFO
Sıra: seviye 0 → 1 → 2 → 3 → ...

DFS — Derinlik Öncelikli

Önce mümkün olduğunca derine in, tıkanınca geri dön.
Veri yapısı: Yığın (Stack) — LIFO
Sıra: bir dal sonuna kadar → geri → diğer dal
Referans Graf — BFS Bu Grafı Dolaşacak
01234567seviye 0seviye 1seviye 2seviye 3
Başlangıç: 0. Seviye 1: {1,2,3}. Seviye 2: {4,5,6}. Seviye 3: {7}.
BFS dolaşma sırası: 0 → 1 → 2 → 3 → 4 → 5 → 6 → 7

BFS Algoritması

BFS üç renkle düğümleri izler: W beyaz = keşfedilmemiş, G gri = kuyrukta (keşfedildi ama komşuları henüz işlenmedi), B siyah = tamamlandı (tüm komşuları işlendi).

BFS pseudocode:
1. Başlangıç düğümünü gri yap ve kuyruğa ekle
2. Kuyruk boş olana kadar tekrarla:
   a. Kuyruktan bir düğüm çıkar (dequeue) → mevcut
   b. Mevcut'un her beyaz komşusu için:
      — Komşuyu gri yap
      — Mesafesini güncelle: mesafe[komşu] = mesafe[mevcut] + 1
      — Ebeveynini kaydet: ebeveyn[komşu] = mevcut
      — Kuyruğa ekle (enqueue)
   c. Mevcut'u siyah yap
3. Tüm erişilebilir düğümler ziyaret edildi ✓
Neden kuyruk (Queue)? FIFO yapısı sayesinde ilk keşfedilen düğümler ilk işlenir. Bu, dalgaların eşit hızda yayılmasını sağlar — seviye 1 tamamen bitmeden seviye 2'ye geçilmez. Stack kullanılsaydı derinlik öncelikli (DFS) olurdu!

Adım Adım — BFS Dolaşma

Referans grafımızda başlangıç düğümü = 0. Her adımda kuyruğun durumunu, hangi düğümün işlendiğini ve mesafe tablosunu takip edelim.

0 Başlangıç: düğüm 0'ı gri yap, kuyruğa ekle.
Kuyruk: 0
Ziyaret: 
Mesafe: [0:0, 1:∞, 2:∞, 3:∞, 4:∞, 5:∞, 6:∞, 7:∞]
1 dequeue(0) → 0'ın komşuları: 1, 2, 3 (hepsi beyaz → gri yap, kuyruğa ekle)
Kuyruk: 123
Ziyaret: 0
Mesafe: [0:0, 1:1, 2:1, 3:1, 4:∞, 5:∞, 6:∞, 7:∞]
Düğüm 0 siyah ✓. Seviye 1 keşfedildi: {1, 2, 3}
2 dequeue(1) → 1'in komşuları: 0(siyah, atla), 2(gri, atla), 4(beyaz → gri)
Kuyruk: 234
Ziyaret: 0, 1
Mesafe: [..., 4:2, 5:∞, 6:∞, 7:∞]
3 dequeue(2) → 2'nin komşuları: 0(siyah), 1(siyah), 5(beyaz → gri)
Kuyruk: 345
Ziyaret: 0, 1, 2
Mesafe: [..., 5:2, 6:∞, 7:∞]
4 dequeue(3) → 3'ün komşuları: 0(siyah), 6(beyaz → gri)
Kuyruk: 456
Ziyaret: 0, 1, 2, 3
Mesafe: [..., 6:2, 7:∞]
Seviye 1 tamamen işlendi ✓. Kuyrukta şimdi sadece seviye 2: {4, 5, 6}
5 dequeue(4) → 4'ün komşuları: 1(siyah), 7(beyaz → gri)
Kuyruk: 567
Ziyaret: 0, 1, 2, 3, 4
Mesafe: [..., 7:3]
6 dequeue(5) → 5'in komşuları: 2(siyah), 7(gri, atla) → yeni keşif yok
7 dequeue(6) → 6'nın komşuları: 3(siyah) → yeni keşif yok
8 dequeue(7) → 7'nin komşuları: 4(siyah), 5(siyah) → yeni keşif yok
Kuyruk: BOŞ
Ziyaret: 0, 1, 2, 3, 4, 5, 6, 7
Kuyruk boş → BFS tamamlandı ✓. Tüm düğümler ziyaret edildi.
BFS Sonuç — Mesafe ve Ebeveyn Tablosu
DüğümMesafeEbeveynSeviyeBFS Sırası
0001.
11012.
21013.
31014.
42125.
52226.
62327.
73438.

BFS — C Implementasyonu

Kuyruk Yapısı

BFS kuyruğa dayanır. Basit bir dairesel kuyruk (circular queue) yeterlidir — en fazla V eleman tutabilir.

queue.c — BFS için basit kuyruk
typedef struct {
    int* veri;
    int  bas, son, kapasite;
} Kuyruk;

Kuyruk* kuyrukOlustur(int kap) {
    Kuyruk* q = malloc(sizeof(Kuyruk));
    q->veri = malloc(kap * sizeof(int));
    q->bas = q->son = 0;
    q->kapasite = kap;
    return q;
}
void  enqueue(Kuyruk* q, int v)  { q->veri[q->son++] = v; }
int   dequeue(Kuyruk* q)          { return q->veri[q->bas++]; }
bool  kuyrukBos(Kuyruk* q)       { return q->bas == q->son; }

BFS — Tam Kod

bfs.c — komşuluk listesi ile BFS
/*
 * BFS — Genişlik Öncelikli Arama
 * graf: komşuluk listesi (önceki bölümdeki ListeGraf)
 * baslangic: kaynak düğüm
 * mesafe[]: her düğümün kaynaktan mesafesi (-1 = ulaşılamaz)
 * ebeveyn[]: BFS ağacında ebeveyn (-1 = kök veya ulaşılamaz)
 */
void bfs(ListeGraf* graf, int baslangic,
         int mesafe[], int ebeveyn[]) {

    int V = graf->dugumSayisi;

    // 1) Başlangıç durumu: tümü keşfedilmemiş
    bool* ziyaret = calloc(V, sizeof(bool));
    for (int i = 0; i < V; i++) {
        mesafe[i]  = -1;
        ebeveyn[i] = -1;
    }

    // 2) Kaynak düğümü başlat
    Kuyruk* q = kuyrukOlustur(V);
    ziyaret[baslangic] = true;
    mesafe[baslangic]  = 0;
    enqueue(q, baslangic);

    // 3) Ana döngü
    while (!kuyrukBos(q)) {
        int u = dequeue(q);

        // u'nun tüm komşularını tara
        KomsulukNode* komsu = graf->listeler[u];
        while (komsu) {
            int v = komsu->hedef;

            if (!ziyaret[v]) {         // beyaz → gri
                ziyaret[v]  = true;
                mesafe[v]   = mesafe[u] + 1;
                ebeveyn[v]  = u;
                enqueue(q, v);
            }
            komsu = komsu->next;
        }
        // u artık siyah (tüm komşuları işlendi)
    }

    free(ziyaret);
    free(q->veri);
    free(q);
}

Karmaşıklık Analizi

ÖlçütKomşuluk ListesiKomşuluk Matrisi
ZamanO(V + E) ✓O(V²)
BellekO(V) (kuyruk + ziyaret + mesafe)O(V)
AçıklamaHer düğüm 1 kez kuyruktan çıkar (V).
Her kenar en fazla 2 kez kontrol edilir (E).
Her düğüm için tüm V sütunu taranır (V×V).
O(V + E) neden optimal? Grafı dolaşmak için her düğüme (V) ve her kenara (E) en az bir kez bakmak zorunludur. BFS tam olarak bunu yapar — ne fazla ne eksik. Bu yüzden BFS asimptotik olarak optimal bir dolaşma algoritmasıdır.

Seviye Seviye Dolaşma (Level-Order)

BFS'in doğal özelliği: düğümleri keşfedildikleri seviyeye göre gruplar. Bu özellik kullanılarak her seviyedeki düğümler ayrı ayrı işlenebilir — ağaç dolaşmadaki level-order traversal'ın graf versiyonudur.

bfs_seviye.c — seviye seviye dolaşma
void bfsSeviye(ListeGraf* graf, int baslangic) {
    int V = graf->dugumSayisi;
    bool* ziyaret = calloc(V, sizeof(bool));
    Kuyruk* q = kuyrukOlustur(V);

    ziyaret[baslangic] = true;
    enqueue(q, baslangic);
    int seviye = 0;

    while (!kuyrukBos(q)) {
        int seviyeBoyut = q->son - q->bas;  // bu seviyedeki düğüm sayısı
        printf("Seviye %d: ", seviye);

        for (int i = 0; i < seviyeBoyut; i++) {
            int u = dequeue(q);
            printf("%d ", u);

            KomsulukNode* k = graf->listeler[u];
            while (k) {
                if (!ziyaret[k->hedef]) {
                    ziyaret[k->hedef] = true;
                    enqueue(q, k->hedef);
                }
                k = k->next;
            }
        }
        printf("\n");
        seviye++;
    }
}
çıktı
Seviye 0: 0
Seviye 1: 1 2 3
Seviye 2: 4 5 6
Seviye 3: 7
BFS Ağacı — Seviye Yapısı
L0L1L2L301234567eb:0eb:0eb:0eb:1eb:2eb:3eb:4
BFS ağacı: ebeveyn kenarları. Her düğümün kökten mesafesi = seviye numarası. Bu ağaç en kısa yol ağacıdır.

En Kısa Yol (Ağırlıksız Graf)

BFS'in en güçlü özelliği: ağırlıksız grafta en kısa yolu garanti eder. BFS her düğümü ilk keşfettiğinde, o düğüme minimum kenar sayısı ile ulaşılmış olur. Çünkü BFS seviye seviye ilerler — seviye k'daki tüm düğümler, seviye k+1'den önce keşfedilir.

Neden BFS en kısa yolu bulur?
BFS seviye 0'dan başlar → seviye 1 → seviye 2 → ... Bir düğüm ilk kez seviye k'da keşfedildiyse, ona tam k kenarla ulaşılmıştır. Daha kısa bir yol olsaydı (k-1 veya daha az), düğüm daha önceki bir seviyede keşfedilirdi — ama keşfedilmedi. Bu çelişki kanıtlar ki BFS mesafesi minimumdur.

Yol Geri İzleme (Path Reconstruction)

BFS'in ebeveyn[] dizisi, kaynak düğümden herhangi bir düğüme en kısa yolu geri izlemek için kullanılır. Hedeften başlayıp ebeveyn takip ederek kaynağa ulaşılır, sonra yol ters çevrilir.

bfs_yol.c — en kısa yol bulma ve yazdırma
/* En kısa yolu geri izle ve yazdır */
void enKisaYolYazdir(int ebeveyn[], int mesafe[],
                     int baslangic, int hedef) {
    if (mesafe[hedef] == -1) {
        printf("%d → %d: ulaşılamaz!\n", baslangic, hedef);
        return;
    }

    // Hedeften kaynağa doğru geri izle
    int yol[1000], uzunluk = 0;
    int curr = hedef;
    while (curr != -1) {
        yol[uzunluk++] = curr;
        curr = ebeveyn[curr];
    }

    // Ters çevirerek yazdır
    printf("%d → %d (mesafe: %d): ",
           baslangic, hedef, mesafe[hedef]);
    for (int i = uzunluk - 1; i >= 0; i--) {
        printf("%d", yol[i]);
        if (i > 0) printf(" → ");
    }
    printf("\n");
}
En Kısa Yol Örnekleri — 0'dan Hedeflere
0 → 7:0147mesafe = 3 ✓
0 → 5:025mesafe = 2 ✓
0 → 6:036mesafe = 2 ✓
0 → 1:01mesafe = 1 ✓
Her yol ebeveyn[] dizisinden geri izlenerek bulundu. Tüm yollar minimum kenar sayısına sahip.
Ağırlıklı graflarda BFS çalışmaz! BFS kenar sayısını minimize eder, kenar ağırlıklarının toplamını değil. Ağırlıklı graflarda en kısa yol için Dijkstra (pozitif ağırlıklar) veya Bellman-Ford (negatif ağırlıklar) kullanılmalıdır.

Demo — Tam Program

bfs_demo.c — tam çalışan program
int main() {
    // Referans grafı oluştur (8 düğüm, yönsüz)
    ListeGraf* g = listeGrafOlustur(8, false);
    listeKenarEkle(g, 0, 1, 1);
    listeKenarEkle(g, 0, 2, 1);
    listeKenarEkle(g, 0, 3, 1);
    listeKenarEkle(g, 1, 4, 1);
    listeKenarEkle(g, 1, 2, 1);
    listeKenarEkle(g, 2, 5, 1);
    listeKenarEkle(g, 3, 6, 1);
    listeKenarEkle(g, 4, 7, 1);
    listeKenarEkle(g, 5, 7, 1);

    // BFS çalıştır
    int mesafe[8], ebeveyn[8];
    bfs(g, 0, mesafe, ebeveyn);

    // Sonuçları yazdır
    printf("=== BFS Sonuçları (kaynak: 0) ===\n");
    printf("Düğüm | Mesafe | Ebeveyn\n");
    printf("-------+--------+--------\n");
    for (int i = 0; i < 8; i++)
        printf("   %d   |   %d    |   %d\n",
               i, mesafe[i], ebeveyn[i]);

    // En kısa yolları yazdır
    printf("\n=== En Kısa Yollar ===\n");
    for (int hedef = 1; hedef < 8; hedef++)
        enKisaYolYazdir(ebeveyn, mesafe, 0, hedef);

    // Seviye seviye dolaşma
    printf("\n=== Seviye Seviye ===\n");
    bfsSeviye(g, 0);

    return 0;
}
çıktı
=== BFS Sonuçları (kaynak: 0) ===
Düğüm | Mesafe | Ebeveyn
-------+--------+--------
   0   |   0    |   -1
   1   |   1    |    0
   2   |   1    |    0
   3   |   1    |    0
   4   |   2    |    1
   5   |   2    |    2
   6   |   2    |    3
   7   |   3    |    4

=== En Kısa Yollar ===
0 → 1 (mesafe: 1): 0 → 1
0 → 2 (mesafe: 1): 0 → 2
0 → 3 (mesafe: 1): 0 → 3
0 → 4 (mesafe: 2): 0 → 1 → 4
0 → 5 (mesafe: 2): 0 → 2 → 5
0 → 6 (mesafe: 2): 0 → 3 → 6
0 → 7 (mesafe: 3): 0 → 1 → 4 → 7

=== Seviye Seviye ===
Seviye 0: 0
Seviye 1: 1 2 3
Seviye 2: 4 5 6
Seviye 3: 7

BFS Kullanım Alanları

UygulamaAçıklamaNeden BFS?
En kısa yol (ağırlıksız)İki düğüm arası minimum kenar sayısıSeviye seviye → ilk keşif = minimum mesafe
Sosyal ağ — arkadaş önerisi"2. derece bağlantılar" (arkadaşın arkadaşı)BFS seviye 2 = 2 hop mesafedeki kişiler
Web crawlerBir sayfadan başlayıp tüm bağlantılı sayfaları keşfetÖnce yakın sayfalar → giderek uzaklara
Bağlılık kontrolüGrafta tüm düğümler bağlı mı? Kaç bileşen var?BFS'ten sonra ziyaret edilmemiş düğüm varsa → bağlı değil
Labirent çözmeGirişten çıkışa en kısa rota2D grid = graf, her hücre = düğüm, 4 komşu
İki parçalılık testiGraf bipartite mi? (2-renklendirilebilir mi?)BFS ile 2-renkleme dene: çelişki varsa bipartite değil
Ağ yayılımıVirüs/bilgi yayılımı simülasyonuHer "tur" bir seviye = bir zaman adımı
GPS/Navigasyon (hop sayısı)Minimum aktarma sayısı (uçuş, metro)Her kenar = 1 aktarma → BFS optimal

Özel Durum — Bağlılık Bileşenleri

bağlılık bileşenleri — BFS ile
int bagliBilesenSay(ListeGraf* graf) {
    int V = graf->dugumSayisi;
    bool* ziyaret = calloc(V, sizeof(bool));
    int bilesen = 0;

    for (int i = 0; i < V; i++) {
        if (!ziyaret[i]) {
            // Yeni bileşen! BFS ile hepsini ziyaret et
            int mesafe[V], ebeveyn[V];
            bfs(graf, i, mesafe, ebeveyn);

            // BFS'in ziyaret ettiği düğümleri işaretle
            for (int j = 0; j < V; j++)
                if (mesafe[j] != -1) ziyaret[j] = true;
            bilesen++;
        }
    }
    free(ziyaret);
    return bilesen;
}

Sonuç

BFS, grafı seviye seviye (genişlik öncelikli) dolaşan temel algoritmadır. İç yapısında kuyruk (FIFO) kullanır — ilk keşfedilen düğüm ilk işlenir. Bu basit prensip, BFS'e ağırlıksız grafta en kısa yol bulma garantisi verir: bir düğüm ilk kez keşfedildiğinde, o düğüme minimum kenar sayısı ile ulaşılmış olur.

Algoritma her düğümü ziyaret edilmiş olarak işaretleyerek sonsuz döngüyü önler. Komşuluk listesi ile zaman karmaşıklığı O(V + E) — asimptotik olarak optimal'dir. Ebeveyn dizisi sayesinde en kısa yol geri izlenebilir, seviye takibi ile katman katman işleme yapılabilir.

BFS'in uygulama alanları çok geniştir: en kısa yol, sosyal ağ önerileri, web crawling, bağlılık kontrolü, labirent çözme, bipartite testi ve ağ yayılımı simülasyonu. BFS ağırlıksız grafta en kısa yolu bulurken, ağırlıklı graflar için Dijkstra veya Bellman-Ford gerekir.

Bölüm 8.2.1 özeti: BFS = genişlik öncelikli arama. Kuyruk (FIFO) kullanır, seviye seviye ilerler. Algoritma: başlangıcı kuyruğa koy → kuyruk boşalana kadar: dequeue(u), u'nun her beyaz komşusu v için: mesafe[v]=mesafe[u]+1, ebeveyn[v]=u, enqueue(v). Karmaşıklık: O(V+E) zaman, O(V) bellek — optimal. En kısa yol garantisi: BFS seviye seviye ilerler → ilk keşif = minimum mesafe (ağırlıksız). Yol geri izleme: ebeveyn[] ile hedeften kaynağa. Uygulamalar: ağırlıksız en kısa yol, sosyal ağ önerisi (2. derece bağlantı), web crawler, bağlılık bileşenleri, labirent, bipartite testi. Sınırlama: ağırlıklı grafta çalışmaz → Dijkstra kullanılmalı. Sonraki bölüm: DFS (Derinlik Öncelikli Arama).
← Veri Yapıları