Bölüm 14: Çizgeler

Veri Yapıları
Temel kavramlarDerece, yol, döngüKomşuluk listesi ve matrisi BFSDFSAğırlıksız en kısa yolDijkstraKruskal ve Prim
Sercan KÜLCÜ · Giresun Üniversitesi · Bilgisayar Mühendisliği

Giriş

Öğrenme Çıktıları

Temel kavramlar

Düğüm, kenar, yön, ağırlık, yol ve bağlantılılık kavramlarını açıklamak.

Gösterimler

Komşuluk matrisi ile komşuluk listesini maliyetleriyle karşılaştırmak.

Gezinme ve sıralama

BFS, DFS ve DAG'lerde topolojik sıralamayı uygulayıp sonuçlarını yorumlamak.

En kısa yol ve MKA

Ağırlıksız BFS, Dijkstra, Kruskal ve Prim algoritmaları için uygun problem türünü seçmek.

Temel Kavramlar

Çizge (Graph)

  • Düğümlerin (vertex / node) ve bu düğümleri birbirine bağlayan kenarların (edge) bir araya gelmesiyle oluşur.
  • Karmaşık ilişkileri, ağları ve yapıları temsil etmek için kullanılır.
  • Çizge teorisi, düğümler ve kenarlar arasındaki ilişkileri inceler.
0 1 2 3 4 kenar düğüm
Bir çizge G = (V, E) ikilisidir: V düğümler kümesi, E kenarlar kümesi.
Örnek: V = {0, 1, 2, 3, 4}, E = {(0,1), (0,4), (1,2), (1,3), (1,4), (2,3), (3,4)} · n = |V| = 5, m = |E| = 7
Ağaç ile farkıKök yoktur, döngü olabilir, bir düğüme birden çok yoldan ulaşılabilir.
İlişki türüÇizge "birçoğa-birçok" ilişkiyi modeller.
Notasyonn = düğüm sayısı, m = kenar sayısı.

Temel Kavramlar

Düğüm (Vertex, Node)

  • Çizgenin temel yapı taşıdır.
  • Şehirler, kişiler, bilgisayarlar gibi nesneleri temsil eder.
  • Düğüm, bir değer (etiket, ad, konum…) saklayabilir.
  • Örnek: haritadaki şehirler ve kavşaklar.
KARADENİZAKDENİZEGEEdirneİstanbulBursaİzmirEskişehirAnkaraAntalyaKonyaAdanaKayseriSamsunSivasGiresunTrabzonErzurumGaziantepDiyarbakırVan

Karayolu haritası: şehirler düğüm, yollar kenar

Harita çizge olarak modellenince "İstanbul'dan Van'a en kısa yol hangisi?" sorusu bir çizge algoritması problemine dönüşür (ör. Dijkstra algoritması).

Temel Kavramlar

Kenar (Edge)

  • Düğümleri birbirine bağlayan bağlantılardır.
  • Kenarlar düğümler arasındaki ilişkiyi temsil eder.
  • (v, w) bir kenar ise v ve w bitişik (komşu, adjacent) düğümlerdir; kenar bu iki düğüme bağlıdır (incident).
  • Örnek: şehirler arasındaki yollar, bilgisayar ağındaki bağlantılar, sosyal ağdaki arkadaşlıklar.

Bir sosyal ağ: kişiler düğüm, ilişkiler kenar

Temel Kavramlar

Derece (Degree)

  • Bir düğümün derecesi, ona bağlı kenar sayısıdır: deg(v).
  • Derecesi 0 olan (yalnız, isolated) düğümler de olabilir.
  • Öz döngü (self-loop) dereceye 2 katkı yapar.
  • Örnek: bir kavşaktaki yolların sayısı.
1 3 3 2 5 2 0 öz döngü yalnız düğüm

Her düğümün içinde kendi derecesi yazıyor

El sıkışma lemmasıHer kenar iki uca birer derece verir: Σ deg(v) = 2mÖrnekte: 1+3+3+2+5+2+0 = 16 = 2·8 kenar.
Yönlü çizgedegiriş derecesi (in-degree): gelen ok sayısı, çıkış derecesi (out-degree): giden ok sayısı.Σ giriş = Σ çıkış = m

Temel Kavramlar

Yönlü Çizge (Digraph)

  • Kenarlar bir düğümden diğerine belirli bir yöndedir: (u, v) ≠ (v, u).
  • Geri dönüş yolu olmayabilir: örnekte B'den A'ya ulaşılamaz.
  • Yönlü çizge (directed graph), kısaca digraph olarak da adlandırılır.
  • Örnek: web sayfaları ve bağlantıları, ders ön koşulları, tek yönlü sokaklar.
A B C E D F
DüğümABCDEF
giriş derecesi021111
çıkış derecesi111120

Temel Kavramlar

Yol (Path) ve Döngü (Cycle)

  • Yol (path): ardışık düğümleri kenarlarla bağlanan düğüm dizisi.
  • Basit yol: hiçbir düğümü tekrar etmeyen yol.
  • Döngü (cycle): aynı düğümde başlayıp biten yol.
  • Basit döngü: başlangıç düğümü dışında hiçbir düğümü tekrar etmez.
  • Çizgelerde döngü olabilir; ağaçta döngü yoktur.
A B C D E F G H I J K L

Yeşil: A-B-C-D-E-F-A · Kırmızı (kesikli): G-H-I-J-K-L-G

Örnek: uçuş rotası. İstanbul → Ankara → İzmir → İstanbul bir döngüdür; aynı şehre uğramadan dönüyorsa basit döngüdür.

Temel Kavramlar

Örnek Çizge

1 2 3 4 5
  • V = {1, 2, 3, 4, 5}
  • E = {(1,2), (1,3), (1,4), (2,5), (3,4), (4,5)}
  • Düğüm 1 ve düğüm 2 komşu.
  • deg(1) = 3, deg(4) = 3, diğerleri 2 → toplam 12 = 2·6 ✓
DiziTürü
1 → 2 → 5basit yol
1 → 3 → 4 → 1basit döngü
1 → 3 → 4 → 1 → 2basit olmayan yol (1 tekrar)
1 → 3 → 4 → 1 → 4 → 1basit olmayan döngü

Temel Kavramlar

Bağlantılı ve Tam Çizge

  • Bağlantılı (connected) çizge: her iki farklı düğüm çifti arasında bir yol vardır.
  • Bağlantılı bileşen (connected component): birbirine yolla ulaşabilen düğümlerin en büyük grubu.
  • Tam (complete) çizge: her iki farklı düğüm çifti arasında bir kenar vardır.
Bağlantılı: 1 bileşen
Bağlantısız: 3 bileşen
Tam çizge K5: 10 kenar

n düğümlü basit yönsüz çizgede m ≤ n(n−1)/2; bu üst sınıra tam çizgede ulaşılır. Bağlantılı bir çizgede m ≥ n − 1.

Temel Kavramlar

Yönlü Çizge Örneği

1 2 3 4 5
  • V = {1, 2, 3, 4, 5}
  • E = {(1,2), (1,4), (2,5), (4,5), (3,1), (4,3)}
  • Düğüm 2, düğüm 1'in komşusu (1 → 2 kenarı var).
  • Düğüm 1, düğüm 2'nin komşusu değil!
DiziTürü
1 → 2 → 5yönlü yol
1 → 4 → 3 → 1yönlü döngü
5 → …5'ten çıkan kenar yok

Yönlü kenar (u, v) sıralı bir çifttir: u kuyruk (başlangıç), v baş (hedef) düğümdür.

Temel Kavramlar

Ağırlıklı Çizge

  • Her kenara bir sayı (ağırlık, weight) atanır: uzaklık, süre, maliyet, kapasite…
  • Bir yolun uzunluğu = üzerindeki kenar ağırlıklarının toplamı. Yönsüz veya yönlü olabilir.
8 10 3 6 5 7 1 2 3 4 5
Ağırlıklı yönsüz: 3 → 4 → 1 yolu 5 + 3 = 8
8 3 6 7 10 5 1 2 3 4 5
Ağırlıklı yönlü: 1 → 4 → 3 yolu 3 + 5 = 8
Doğrudan kenar her zaman en kısa yol değildir: yönsüz çizgede 1–3 kenarı 10, ama 1 → 4 → 3 yolu yalnızca 8.

Temel Kavramlar

Çizge Soyut Veri Tipi (Graph ADT)

Goodrich'teki Graph arayüzünün temel işlemleri (V: düğüm, E: kenar):

İşlemAçıklama
numVertices(), numEdges()Düğüm sayısı n, kenar sayısı m
vertices(), edges()Tüm düğümler / tüm kenarlar üzerinde gezinme
getEdge(u, v)u'dan v'ye kenar varsa onu, yoksa null döndürür
endVertices(e), opposite(v, e)Kenarın iki ucu / e kenarının v dışındaki ucu
outDegree(v), inDegree(v)Çıkış / giriş derecesi (yönsüzde ikisi eşit)
outgoingEdges(v), incomingEdges(v)v'den çıkan / v'ye gelen kenarlar
insertVertex(x), insertEdge(u, v, x)Yeni düğüm / yeni kenar ekler
removeVertex(v), removeEdge(e)Düğümü (bağlı kenarlarıyla) / kenarı siler

Bu işlemlerin maliyeti, çizgenin bellekte nasıl temsil edildiğine bağlıdır → sonraki alt başlık: Çizge Gösterimleri.

Çizge Gösterimleri

Çizge Nasıl Saklanır? Üç Temel Gösterim

Kenar listesiTüm kenarlar tek bir listede tutulur.[(A,B), (A,E), …]
Komşuluk listesiHer düğüm için komşularının listesi tutulur.V[i] = {j, k, l}
Komşuluk matrisin×n iki boyutlu dizi; hücre, kenarın varlığını gösterir.M[i][j] = 1
A B C D E

Kenar listesi (edge list) en basit gösterimdir:

(A, B)(A, E)(B, C)(B, E)(C, D)(D, E)
  • Alan O(n + m); kenar eklemek O(1).
  • Ama "u ile v komşu mu?" ya da "u'nun komşuları kim?" için tüm listeyi taramak gerekir: O(m).

Çizge Gösterimleri

Komşuluk Matrisi (Adjacency Matrix)

  • n×n boyutunda iki boyutlu bir dizidir: matris[i][j] = 1, düğüm i'den j'ye kenar varsa; yoksa 0.
  • Ağırlıklı çizgede matris[i][j] kenarın ağırlığını tutar; kenar yoksa ∞ (veya özel bir değer).
  • Yönsüz çizgede matris simetriktir: matris[i][j] == matris[j][i].
  • Alan karmaşıklığı O(n²); düğüm sayısı arttıkça bellek hızla büyür.
0 1 2 3 0 0 0 1 1 0 1 1 1 0 1 0 2 2 1 1 0 1 3 3 0 0 1 0 ← m[1][2]: tek hücre, O(1) ← 2'nin komşuları: tüm satır, O(n) simetrik: m[i][j] = m[j][i]

Kolay

  • İki düğüm arasında kenar var mı? O(1)
  • Kenar ekleme / silme O(1)

Zor

  • Bir düğümün komşularını bulmak: tüm satır, O(n)
  • Seyrek çizgede hücrelerin çoğu boş (0)

Çizge Gösterimleri

Komşuluk Matrisi: Üç Örnek

A B C D E
ABCDE
A01001
B10101
C01010
D00101
E11010

Yönsüz çizge: her kenar iki hücreye yazılır, matris köşegene göre simetrik. Satır toplamı = derece (B: 3).

A B C D E
ABCDE
A01001
B00110
C00000
D10101
E01010

Yönlü çizge: satır = kaynak, sütun = hedef. Simetrik değil; satır toplamı çıkış, sütun toplamı giriş derecesi.

4 3 3 2 2 5 2 A B C D E
ABCDE
A04∞∞∞
B∞033∞
C2∞0∞2
D∞∞∞0∞
E∞5∞20

Ağırlıklı çizge: hücrede ağırlık, kenar yoksa ∞ (köşegende 0). Boş hücreye 0 yazmak, 0 ağırlıklı bir kenarla karıştırılabilir.

Çizge Gösterimleri

Komşuluk Listesi (Adjacency List)

  • n düğüm için n adet liste (çoğunlukla bağlı liste veya dinamik dizi) tutulur.
  • liste[i], düğüm i'ye komşu olan düğümleri (ağırlıklıysa ağırlıklarıyla) içerir.
  • Yönsüz çizgede her kenar (v, w) iki listeye de eklenir: w, v'nin listesine; v, w'nin listesine.
  • Alan karmaşıklığı O(n + m); seyrek çizgeler için idealdir.
0 1 2 3 0 1 2 1 0 2 2 0 1 3 3 2 ← 2–3 var mı? listeyi tara: O(deg 2) toplam kayıt 2m = 8 → alan O(n + m)

Kolay

  • Bir düğümün komşularını gezmek: O(deg(v))
  • Kenar ekleme O(1)

Zor

  • u ile v arasında kenar var mı? Listeyi taramak gerekir: O(deg(u))

Çizge Gösterimleri

Komşuluk Listesi: Üç Örnek

A B C D E
A B E B A C E C B D D C E E A B D

Yönsüz: 6 kenar → listelerde 12 kayıt (her kenar iki kez). Liste uzunluğu = derece.

A B C D E
A B E B C D C (boş) D A C E E B D

Yönlü: yalnızca çıkan kenarlar listelenir; 9 kenar → 9 kayıt. C'den çıkan kenar yok, listesi boş.

4 3 3 2 2 5 2 A B C D E
A B 4 B C 3 D 3 C A 2 E 2 D (boş) E B 5 D 2

Ağırlıklı: her kayıt (komşu, ağırlık) çifti tutar; ör. B'nin listesi: (C, 3), (D, 3).

Çizge Gösterimleri

Gösterimlerin Bellek ve İşlem Maliyeti

İşlem (n düğüm, m kenar)Kenar listesiKomşuluk listesiKomşuluk matrisi
BellekO(n + m)O(n + m)O(n²)
u–v kenarı var mı? getEdgeO(m)yönsüz: O(min(deg u, deg v))
yönlü u→v: O(outDeg u)
O(1)
v'nin komşularını gezO(m)O(deg v)O(n)
Seyrek çizge (m ≈ n)Yol ağları, sosyal ağlar → komşuluk listesi. n = 10⁶ düğümde matris 10¹² hücre ister!
Yoğun çizge (m ≈ n²)Sık "kenar var mı?" sorgusu → komşuluk matrisi.

Çizge Gösterimleri

Java ile Komşuluk Listesi

class Cizge {
    private final int n;                                  // düğümler: 0..n-1
    private final List<List<Integer>> komsu = new ArrayList<>();
    Cizge(int n) {
        this.n = n;
        for (int i = 0; i < n; i++)
            komsu.add(new ArrayList<>());
    }
    void kenarEkle(int u, int v) {
        komsu.get(u).add(v);
        komsu.get(v).add(u);                  // yönlü çizgede bu satır yok
    }
    List<Integer> komsular(int u) { return komsu.get(u); }   // O(1)
    int derece(int u) { return komsu.get(u).size(); }
}
Matris karşılığıboolean[][] m = new boolean[n][n]; kenar ekle: m[u][v] = m[v][u] = true; sorgu m[u][v] O(1).
Ağırlıklı çizgeListe öğesi int[]{v, w} veya küçük bir Kenar sınıfı; matriste int[][], kenar yoksa Integer.MAX_VALUE.

Çizge Gösterimleri · Kodu adım adım çalıştır

Kod İzleme: Komşuluk Listesi Kurma

Cizge(int n) {
  this.n = n;
  for (int i = 0; i < n; i++)
    komsu.add(new ArrayList<>());
}
void kenarEkle(int u, int v) {
  komsu.get(u).add(v);
  komsu.get(v).add(u);  // yönlüde yok
}
// main:
Cizge g = new Cizge(5);
int[][] E = {{0,1}, {0,4}, {1,2},
             {1,4}, {2,3}, {3,4}};
for (int[] e : E) g.kenarEkle(e[0], e[1]);
0 1 2 3 4 komsu

new Cizge(5): yapıcı çağrılır; n = 5 atanır. komsu henüz boş bir dış liste.

0 1 2 3 4 komsu 0 [ ]

i = 0: 0 numaralı düğüm için boş bir iç liste eklenir.

0 1 2 3 4 komsu 0 [ ] 1 [ ]

i = 1: 1 numaralı düğüm için boş bir iç liste eklenir.

0 1 2 3 4 komsu 0 [ ] 1 [ ] 2 [ ]

i = 2: 2 numaralı düğüm için boş bir iç liste eklenir.

0 1 2 3 4 komsu 0 [ ] 1 [ ] 2 [ ] 3 [ ]

i = 3: 3 numaralı düğüm için boş bir iç liste eklenir.

0 1 2 3 4 komsu 0 [ ] 1 [ ] 2 [ ] 3 [ ] 4 [ ]

i = 4: 4 numaralı düğüm için boş bir iç liste eklenir. Artık her düğümün (boş) komşu listesi var.

0 1 2 3 4 komsu 0 1 1 [ ] 2 [ ] 3 [ ] 4 [ ]

Kenar 0–1: 1, 0'ın listesinin sonuna eklenir.

0 1 2 3 4 komsu 0 1 1 0 2 [ ] 3 [ ] 4 [ ]

Yönsüz çizge: aynı kenar ters yönde de eklenir → 0, 1'in listesine.

0 1 2 3 4 komsu 0 1 4 1 0 2 [ ] 3 [ ] 4 [ ]

Kenar 0–4: 4, 0'ın listesinin sonuna eklenir.

0 1 2 3 4 komsu 0 1 4 1 0 2 [ ] 3 [ ] 4 0

Yönsüz çizge: aynı kenar ters yönde de eklenir → 0, 4'ün listesine.

0 1 2 3 4 komsu 0 1 4 1 0 2 2 [ ] 3 [ ] 4 0

Kenar 1–2: 2, 1'in listesinin sonuna eklenir.

0 1 2 3 4 komsu 0 1 4 1 0 2 2 1 3 [ ] 4 0

Yönsüz çizge: aynı kenar ters yönde de eklenir → 1, 2'nin listesine.

0 1 2 3 4 komsu 0 1 4 1 0 2 4 2 1 3 [ ] 4 0

Kenar 1–4: 4, 1'in listesinin sonuna eklenir.

0 1 2 3 4 komsu 0 1 4 1 0 2 4 2 1 3 [ ] 4 0 1

Yönsüz çizge: aynı kenar ters yönde de eklenir → 1, 4'ün listesine.

0 1 2 3 4 komsu 0 1 4 1 0 2 4 2 1 3 3 [ ] 4 0 1

Kenar 2–3: 3, 2'nin listesinin sonuna eklenir.

0 1 2 3 4 komsu 0 1 4 1 0 2 4 2 1 3 3 2 4 0 1

Yönsüz çizge: aynı kenar ters yönde de eklenir → 2, 3'ün listesine.

0 1 2 3 4 komsu 0 1 4 1 0 2 4 2 1 3 3 2 4 4 0 1

Kenar 3–4: 4, 3'ün listesinin sonuna eklenir.

0 1 2 3 4 komsu 0 1 4 1 0 2 4 2 1 3 3 2 4 4 0 1 3

Yönsüz çizge: aynı kenar ters yönde de eklenir → 3, 4'ün listesine.

0 1 2 3 4 komsu 0 1 4 1 0 2 4 2 1 3 3 2 4 4 0 1 3

Bitti: 6 kenar → listelerde 2·6 = 12 kayıt. Her kenarEkle O(1); bellek O(n + m). derece(1) = liste uzunluğu = 3.

Çizge Gösterimleri · Kodu adım adım çalıştır

Kod İzleme: Komşuluk Matrisi Kurma

0 1 2 3 4 0 1 2 3 4 0 0 0 0 0 0 1 0 0 0 0 0 2 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 0 m[satır][sütun] (1 = true)

5×5 boolean matris oluşturulur; Java tüm hücreleri false (0) ile başlatır. Bellek O(n²) = 25 hücre.

0 1 2 3 4 0 1 2 3 4 0 0 1 0 0 0 1 0 0 0 0 0 2 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 0 m[satır][sütun] (1 = true)

Kenar 0–1: m[0][1] = true (satır 0, sütun 1).

0 1 2 3 4 0 1 2 3 4 0 0 1 0 0 0 1 1 0 0 0 0 2 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 0 m[satır][sütun] (1 = true)

Simetrik hücre: m[1][0] = true. Yönsüz çizgenin matrisi köşegene göre simetriktir.

0 1 2 3 4 0 1 2 3 4 0 0 1 0 0 1 1 1 0 0 0 0 2 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 0 m[satır][sütun] (1 = true)

Kenar 0–4: m[0][4] = true (satır 0, sütun 4).

0 1 2 3 4 0 1 2 3 4 0 0 1 0 0 1 1 1 0 0 0 0 2 0 0 0 0 0 3 0 0 0 0 0 4 1 0 0 0 0 m[satır][sütun] (1 = true)

Simetrik hücre: m[4][0] = true. Yönsüz çizgenin matrisi köşegene göre simetriktir.

0 1 2 3 4 0 1 2 3 4 0 0 1 0 0 1 1 1 0 1 0 0 2 0 0 0 0 0 3 0 0 0 0 0 4 1 0 0 0 0 m[satır][sütun] (1 = true)

Kenar 1–2: m[1][2] = true (satır 1, sütun 2).

0 1 2 3 4 0 1 2 3 4 0 0 1 0 0 1 1 1 0 1 0 0 2 0 1 0 0 0 3 0 0 0 0 0 4 1 0 0 0 0 m[satır][sütun] (1 = true)

Simetrik hücre: m[2][1] = true. Yönsüz çizgenin matrisi köşegene göre simetriktir.

0 1 2 3 4 0 1 2 3 4 0 0 1 0 0 1 1 1 0 1 0 1 2 0 1 0 0 0 3 0 0 0 0 0 4 1 0 0 0 0 m[satır][sütun] (1 = true)

Kenar 1–4: m[1][4] = true (satır 1, sütun 4).

0 1 2 3 4 0 1 2 3 4 0 0 1 0 0 1 1 1 0 1 0 1 2 0 1 0 0 0 3 0 0 0 0 0 4 1 1 0 0 0 m[satır][sütun] (1 = true)

Simetrik hücre: m[4][1] = true. Yönsüz çizgenin matrisi köşegene göre simetriktir.

0 1 2 3 4 0 1 2 3 4 0 0 1 0 0 1 1 1 0 1 0 1 2 0 1 0 1 0 3 0 0 0 0 0 4 1 1 0 0 0 m[satır][sütun] (1 = true)

Kenar 2–3: m[2][3] = true (satır 2, sütun 3).

0 1 2 3 4 0 1 2 3 4 0 0 1 0 0 1 1 1 0 1 0 1 2 0 1 0 1 0 3 0 0 1 0 0 4 1 1 0 0 0 m[satır][sütun] (1 = true)

Simetrik hücre: m[3][2] = true. Yönsüz çizgenin matrisi köşegene göre simetriktir.

0 1 2 3 4 0 1 2 3 4 0 0 1 0 0 1 1 1 0 1 0 1 2 0 1 0 1 0 3 0 0 1 0 1 4 1 1 0 0 0 m[satır][sütun] (1 = true)

Kenar 3–4: m[3][4] = true (satır 3, sütun 4).

0 1 2 3 4 0 1 2 3 4 0 0 1 0 0 1 1 1 0 1 0 1 2 0 1 0 1 0 3 0 0 1 0 1 4 1 1 0 1 0 m[satır][sütun] (1 = true)

Simetrik hücre: m[4][3] = true. Yönsüz çizgenin matrisi köşegene göre simetriktir.

0 1 2 3 4 0 1 2 3 4 0 0 1 0 0 1 1 1 0 1 0 1 2 0 1 0 1 0 3 0 0 1 0 1 4 1 1 0 1 0 m[satır][sütun] (1 = true)

Bitti: 12 hücre true, 13'ü boşa false. "2–4 kenarı var mı?" → m[2][4] tek erişim, O(1); ama 2'nin komşularını bulmak için tüm satır taranır: O(n).

boolean[][] m = new boolean[n][n];
void kenarEkle(int u, int v) {
  m[u][v] = true;
  m[v][u] = true;  // yönlü çizgede yok
}
// main: aynı 6 kenar (n = 5)
for (int[] e : E) g.kenarEkle(e[0], e[1]);

Gezinme (BFS / DFS)

Gezinme Algoritmaları

Gezinme (traversal): bir başlangıç düğümünden ulaşılabilen tüm düğümleri, her birini bir kez sistematik olarak ziyaret etmek.

Genişlik Öncelikli Arama (BFS)Breadth-First Search. Önce tüm yakın komşular, sonra onların komşuları… Seviye seviye ilerler.yardımcı yapı: kuyruk (FIFO)
Derinlik Öncelikli Arama (DFS)Depth-First Search. Bir yol boyunca gidebildiği kadar derine iner, çıkmazda geri döner.yardımcı yapı: yığın (LIFO) / özyineleme
Ağaçtan farkı: çizgede döngü olabilir, aynı düğüme birden çok yoldan gelinebilir → ziyaret edildi işareti (ör. boolean[] ziyaret) şarttır; yoksa algoritma sonsuza kadar döner.

Gezinme (BFS / DFS)

Genişlik Öncelikli Arama (BFS)

  • Düğümleri seviye seviye keşfeder: önce başlangıca 1 kenar uzaklıktakiler, sonra 2 kenar uzaklıktakiler…
  • Kuyruk yapısını kullanır: ilk keşfedilen ilk işlenir.
  • Her düğüm yalnızca bir kez ziyaret edilir.
seviye 0 seviye 1 seviye 2 s a b c d e 1 2 3 4 5 6

Numara = ziyaret sırası; kalın = BFS ağacı

Artıları

  • Ağırlıksız çizgede en kısa yolu (en az kenar) bulur.
  • Yakın düğümleri hızlı keşfeder.

Eksisi

  • Bellek kullanımı yüksek olabilir: bir seviyenin tamamı kuyrukta bekler.
Örnek: sosyal ağda "arkadaşımın arkadaşları" (2. seviye), bir web tarayıcının (crawler) siteyi katman katman gezmesi.

Gezinme (BFS / DFS)

BFS Algoritması

Sözde kod
BFS(başlangıç):
  kuyruk.ekle(başlangıç)
  başlangıç.ziyaretEdildi()
  while kuyruk boş değil:
    w = kuyruk.çıkar()
    for w'nin ziyaret edilmemiş
        her komşusu u:
      u.ziyaretEdildi()
      kuyruk.ekle(u)

Düğüm kuyruğa girerken işaretlenir; böylece aynı düğüm kuyruğa iki kez girmez.

Java
void bfs(int s) {
  boolean[] ziyaret = new boolean[n];
  Queue<Integer> q = new ArrayDeque<>();
  ziyaret[s] = true;  q.add(s);
  while (!q.isEmpty()) {
    int w = q.poll();
    System.out.print(w + " ");
    for (int u : komsu.get(w))
      if (!ziyaret[u]) {
        ziyaret[u] = true;
        q.add(u);
      }
  }
}

Gezinme (BFS / DFS) · Kodu adım adım çalıştır

Kod İzleme: bfs(A)

void bfs(int s) {
  boolean[] ziyaret = new boolean[n];
  Queue<Integer> q = new ArrayDeque<>();
  ziyaret[s] = true;  q.add(s);
  while (!q.isEmpty()) {
    int w = q.poll();
    System.out.print(w + " ");
    for (int u : komsu.get(w))
      if (!ziyaret[u]) {
        ziyaret[u] = true;
        q.add(u);
      }
  }
}
I A B C D H G F E q (ön → arka) (boş) ziyaret[] A F B F C F D F E F F F G F H F I F görülmedi kuyrukta işleniyor işlendi

s = A (A=0, B=1, …, I=8; komşular alfabetik). ziyaret tümü false, kuyruk boş.

I A B C D H G F E q (ön → arka) A ziyaret[] A T B F C F D F E F F F G F H F I F görülmedi kuyrukta işleniyor işlendi

A kuyruğa girerken işaretlenir: ziyaret[A] = true, q = [A].

I A B C D H G F E q (ön → arka) (boş) ziyaret[] A T B F C F D F E F F F G F H F I F görülmedi kuyrukta işleniyor işlendi

Kuyruğun önündeki A çıkarılır (poll) ve yazdırılır. Şimdi komşuları B, F, I taranır.

I A B C D H G F E q (ön → arka) B ziyaret[] A T B T C F D F E F F F G F H F I F görülmedi kuyrukta işleniyor işlendi

u = B ziyaret edilmemiş → işaretlenir ve kuyruğun arkasına eklenir (seviye 1).

I A B C D H G F E q (ön → arka) B F ziyaret[] A T B T C F D F E F F T G F H F I F görülmedi kuyrukta işleniyor işlendi

u = F ziyaret edilmemiş → işaretlenir ve kuyruğun arkasına eklenir (seviye 1).

I A B C D H G F E q (ön → arka) B F I ziyaret[] A T B T C F D F E F F T G F H F I T görülmedi kuyrukta işleniyor işlendi

u = I ziyaret edilmemiş → işaretlenir ve kuyruğun arkasına eklenir (seviye 1).

I A B C D H G F E q (ön → arka) F I ziyaret[] A T B T C F D F E F F T G F H F I T görülmedi kuyrukta işleniyor işlendi

Kuyruğun önündeki B çıkarılır (poll) ve yazdırılır. Şimdi komşuları A, C, E taranır.

I A B C D H G F E q (ön → arka) F I ziyaret[] A T B T C F D F E F F T G F H F I T görülmedi kuyrukta işleniyor işlendi

u = A: zaten ziyaret edilmiş → atlanır. Ziyaret işareti olmasa kuyruğa tekrar girerdi.

I A B C D H G F E q (ön → arka) F I C ziyaret[] A T B T C T D F E F F T G F H F I T görülmedi kuyrukta işleniyor işlendi

u = C ziyaret edilmemiş → işaretlenir ve kuyruğun arkasına eklenir (seviye 2).

I A B C D H G F E q (ön → arka) F I C E ziyaret[] A T B T C T D F E T F T G F H F I T görülmedi kuyrukta işleniyor işlendi

u = E ziyaret edilmemiş → işaretlenir ve kuyruğun arkasına eklenir (seviye 2).

I A B C D H G F E q (ön → arka) I C E ziyaret[] A T B T C T D F E T F T G F H F I T görülmedi kuyrukta işleniyor işlendi

Kuyruğun önündeki F çıkarılır (poll) ve yazdırılır. Şimdi komşuları A, G taranır.

I A B C D H G F E q (ön → arka) I C E ziyaret[] A T B T C T D F E T F T G F H F I T görülmedi kuyrukta işleniyor işlendi

u = A: zaten ziyaret edilmiş → atlanır.

I A B C D H G F E q (ön → arka) I C E G ziyaret[] A T B T C T D F E T F T G T H F I T görülmedi kuyrukta işleniyor işlendi

u = G ziyaret edilmemiş → işaretlenir ve kuyruğun arkasına eklenir (seviye 2).

I A B C D H G F E q (ön → arka) C E G ziyaret[] A T B T C T D F E T F T G T H F I T görülmedi kuyrukta işleniyor işlendi

Kuyruğun önündeki I çıkarılır (poll) ve yazdırılır. Şimdi komşusu A taranır.

I A B C D H G F E q (ön → arka) C E G ziyaret[] A T B T C T D F E T F T G T H F I T görülmedi kuyrukta işleniyor işlendi

u = A: zaten ziyaret edilmiş → atlanır.

Gezinme (BFS / DFS) · Kodu adım adım çalıştır

Kod İzleme: bfs(A) (devam)

void bfs(int s) {
  boolean[] ziyaret = new boolean[n];
  Queue<Integer> q = new ArrayDeque<>();
  ziyaret[s] = true;  q.add(s);
  while (!q.isEmpty()) {
    int w = q.poll();
    System.out.print(w + " ");
    for (int u : komsu.get(w))
      if (!ziyaret[u]) {
        ziyaret[u] = true;
        q.add(u);
      }
  }
}
I A B C D H G F E q (ön → arka) E G ziyaret[] A T B T C T D F E T F T G T H F I T görülmedi kuyrukta işleniyor işlendi

Kuyruğun önündeki C çıkarılır (poll) ve yazdırılır. Şimdi komşuları B, D, E taranır.

I A B C D H G F E q (ön → arka) E G ziyaret[] A T B T C T D F E T F T G T H F I T görülmedi kuyrukta işleniyor işlendi

u = B: zaten ziyaret edilmiş → atlanır.

I A B C D H G F E q (ön → arka) E G D ziyaret[] A T B T C T D T E T F T G T H F I T görülmedi kuyrukta işleniyor işlendi

u = D ziyaret edilmemiş → işaretlenir ve kuyruğun arkasına eklenir (seviye 3).

I A B C D H G F E q (ön → arka) E G D ziyaret[] A T B T C T D T E T F T G T H F I T görülmedi kuyrukta işleniyor işlendi

u = E: zaten ziyaret edilmiş → atlanır.

I A B C D H G F E q (ön → arka) G D ziyaret[] A T B T C T D T E T F T G T H F I T görülmedi kuyrukta işleniyor işlendi

Kuyruğun önündeki E çıkarılır (poll) ve yazdırılır. Şimdi komşuları B, C, G taranır.

I A B C D H G F E q (ön → arka) G D ziyaret[] A T B T C T D T E T F T G T H F I T görülmedi kuyrukta işleniyor işlendi

u = B, C, G: hepsi zaten ziyaret edilmiş → atlanır.

I A B C D H G F E q (ön → arka) D ziyaret[] A T B T C T D T E T F T G T H F I T görülmedi kuyrukta işleniyor işlendi

Kuyruğun önündeki G çıkarılır (poll) ve yazdırılır. Şimdi komşuları D, E, F taranır.

I A B C D H G F E q (ön → arka) D ziyaret[] A T B T C T D T E T F T G T H F I T görülmedi kuyrukta işleniyor işlendi

u = D, E, F: hepsi zaten ziyaret edilmiş → atlanır.

I A B C D H G F E q (ön → arka) (boş) ziyaret[] A T B T C T D T E T F T G T H F I T görülmedi kuyrukta işleniyor işlendi

Kuyruğun önündeki D çıkarılır (poll) ve yazdırılır. Şimdi komşuları C, G, H taranır.

I A B C D H G F E q (ön → arka) (boş) ziyaret[] A T B T C T D T E T F T G T H F I T görülmedi kuyrukta işleniyor işlendi

u = C, G: hepsi zaten ziyaret edilmiş → atlanır.

I A B C D H G F E q (ön → arka) H ziyaret[] A T B T C T D T E T F T G T H T I T görülmedi kuyrukta işleniyor işlendi

u = H ziyaret edilmemiş → işaretlenir ve kuyruğun arkasına eklenir (seviye 4).

I A B C D H G F E q (ön → arka) (boş) ziyaret[] A T B T C T D T E T F T G T H T I T görülmedi kuyrukta işleniyor işlendi

Kuyruğun önündeki H çıkarılır (poll) ve yazdırılır. Şimdi komşusu D taranır.

I A B C D H G F E q (ön → arka) (boş) ziyaret[] A T B T C T D T E T F T G T H T I T görülmedi kuyrukta işleniyor işlendi

u = D: zaten ziyaret edilmiş → atlanır.

I A B C D H G F E q (ön → arka) (boş) ziyaret[] A T B T C T D T E T F T G T H T I T görülmedi kuyrukta işleniyor işlendi

Kuyruk boş → biter. Sıra A B F I C E G D H: seviye seviye. Her düğüm bir kez kuyruğa girer, her liste bir kez taranır → O(n + m).

Gezinme (BFS / DFS)

Derinlik Öncelikli Arama (DFS)

  • Düğümleri bir yol boyunca keşfeder: gidebildiği kadar derine iner.
  • Çıkmaza gelince (ziyaret edilmemiş komşu kalmayınca) geri döner (backtracking) ve başka dalı dener.
  • Yığın (stack) yapısı veya özyinelemeli çağrılar kullanılır.
s a b c d e 1 2 3 4 5 6

s→a→d→b derine; çıkmazda geri, sonra c→e

Artıları

  • Bellek kullanımı genellikle düşüktür (yalnızca mevcut yol yığında).
  • Bir yolun sonuna kadar gitme yeteneği sağlar.

Eksisi

  • En kısa yolu garanti etmez.
Kullanım: labirent çözme, döngü tespiti, bağlantılı bileşenleri bulma ve yönlü döngüsüz çizgelerde topolojik sıralama.

Gezinme (BFS / DFS)

DFS Algoritması

Özyinelemeli
void dfs(int v, boolean[] ziyaret) {
  ziyaret[v] = true;
  System.out.print(v + " ");
  for (int u : komsu.get(v))
    if (!ziyaret[u])
      dfs(u, ziyaret);
}

Özyineleme, yığını bizim yerimize çağrı yığını ile tutar.

Açık yığınla
void dfsYigin(int s) {
  boolean[] ziyaret = new boolean[n];
  Deque<Integer> yigin = new ArrayDeque<>();
  yigin.push(s);  ziyaret[s] = true;
  while (!yigin.isEmpty()) {
    int v = yigin.peek();
    Integer yeni = null;
    for (int u : komsu.get(v))
      if (!ziyaret[u]) { yeni = u; break; }
    if (yeni == null) yigin.pop(); // geri
    else { ziyaret[yeni] = true;
           yigin.push(yeni); }
  }
}

Gezinme (BFS / DFS) · Kodu adım adım çalıştır

Kod İzleme: dfs(A) (özyinelemeli)

void dfs(int v, boolean[] ziyaret) {
  ziyaret[v] = true;
  System.out.print(v + " ");
  for (int u : komsu.get(v))
    if (!ziyaret[u])
      dfs(u, ziyaret);
}
I A B C D H G F E ziyaret[] A T B F C F D F E F F F G F H F I F görülmedi yığında üstte çıktı

dfs(A, ziyaret) çağrıldı (A=0, B=1, …, I=8; komşular alfabetik). A işaretlenir ve yazdırılır.

I A B C D H G F E ziyaret[] A T B T C F D F E F F F G F H F I F görülmedi yığında üstte çıktı

A'nın komşusu B ziyaret edilmemiş → dfs(B) çağrılır: yeni çerçeve açılır, B işaretlenip yazdırılır.

I A B C D H G F E ziyaret[] A T B T C F D F E F F F G F H F I F görülmedi yığında üstte çıktı

B'nin komşusu A zaten ziyaret edilmiş → atla.

I A B C D H G F E ziyaret[] A T B T C T D F E F F F G F H F I F görülmedi yığında üstte çıktı

B'nin komşusu C ziyaret edilmemiş → dfs(C) çağrılır: yeni çerçeve açılır, C işaretlenip yazdırılır.

I A B C D H G F E ziyaret[] A T B T C T D F E F F F G F H F I F görülmedi yığında üstte çıktı

C'nin komşusu B zaten ziyaret edilmiş → atla.

I A B C D H G F E ziyaret[] A T B T C T D T E F F F G F H F I F görülmedi yığında üstte çıktı

C'nin komşusu D ziyaret edilmemiş → dfs(D) çağrılır: yeni çerçeve açılır, D işaretlenip yazdırılır.

I A B C D H G F E ziyaret[] A T B T C T D T E F F F G F H F I F görülmedi yığında üstte çıktı

D'nin komşusu C zaten ziyaret edilmiş → atla.

I A B C D H G F E ziyaret[] A T B T C T D T E F F F G T H F I F görülmedi yığında üstte çıktı

D'nin komşusu G ziyaret edilmemiş → dfs(G) çağrılır: yeni çerçeve açılır, G işaretlenip yazdırılır.

I A B C D H G F E ziyaret[] A T B T C T D T E F F F G T H F I F görülmedi yığında üstte çıktı

G'nin komşusu D zaten ziyaret edilmiş → atla.

I A B C D H G F E ziyaret[] A T B T C T D T E T F F G T H F I F görülmedi yığında üstte çıktı

G'nin komşusu E ziyaret edilmemiş → dfs(E) çağrılır: yeni çerçeve açılır, E işaretlenip yazdırılır.

I A B C D H G F E ziyaret[] A T B T C T D T E T F F G T H F I F görülmedi yığında üstte çıktı

E'nin komşuları B, C, G zaten ziyaret edilmiş → atla.

I A B C D H G F E ziyaret[] A T B T C T D T E T F F G T H F I F görülmedi yığında üstte çıktı

E'nin gidilecek komşusu kalmadı → dfs(E) biter, çerçeve yığından çıkar (geri dönüş).

I A B C D H G F E ziyaret[] A T B T C T D T E T F T G T H F I F görülmedi yığında üstte çıktı

G'nin komşusu F ziyaret edilmemiş → dfs(F) çağrılır: yeni çerçeve açılır, F işaretlenip yazdırılır.

I A B C D H G F E ziyaret[] A T B T C T D T E T F T G T H F I F görülmedi yığında üstte çıktı

F'nin komşuları A, G zaten ziyaret edilmiş → atla.

I A B C D H G F E ziyaret[] A T B T C T D T E T F T G T H F I F görülmedi yığında üstte çıktı

F'nin gidilecek komşusu kalmadı → dfs(F) biter, çerçeve yığından çıkar (geri dönüş).

Gezinme (BFS / DFS) · Kodu adım adım çalıştır

Kod İzleme: dfs(A) (özyinelemeli) (devam)

void dfs(int v, boolean[] ziyaret) {
  ziyaret[v] = true;
  System.out.print(v + " ");
  for (int u : komsu.get(v))
    if (!ziyaret[u])
      dfs(u, ziyaret);
}
I A B C D H G F E ziyaret[] A T B T C T D T E T F T G T H F I F görülmedi yığında üstte çıktı

G'nin gidilecek komşusu kalmadı → dfs(G) biter, çerçeve yığından çıkar (geri dönüş).

I A B C D H G F E ziyaret[] A T B T C T D T E T F T G T H T I F görülmedi yığında üstte çıktı

D'nin komşusu H ziyaret edilmemiş → dfs(H) çağrılır: yeni çerçeve açılır, H işaretlenip yazdırılır.

I A B C D H G F E ziyaret[] A T B T C T D T E T F T G T H T I F görülmedi yığında üstte çıktı

H'nin komşusu D zaten ziyaret edilmiş → atla.

I A B C D H G F E ziyaret[] A T B T C T D T E T F T G T H T I F görülmedi yığında üstte çıktı

H'nin gidilecek komşusu kalmadı → dfs(H) biter, çerçeve yığından çıkar (geri dönüş).

I A B C D H G F E ziyaret[] A T B T C T D T E T F T G T H T I F görülmedi yığında üstte çıktı

D'nin gidilecek komşusu kalmadı → dfs(D) biter, çerçeve yığından çıkar (geri dönüş).

I A B C D H G F E ziyaret[] A T B T C T D T E T F T G T H T I F görülmedi yığında üstte çıktı

C'nin komşusu E zaten ziyaret edilmiş → atla.

I A B C D H G F E ziyaret[] A T B T C T D T E T F T G T H T I F görülmedi yığında üstte çıktı

C'nin gidilecek komşusu kalmadı → dfs(C) biter, çerçeve yığından çıkar (geri dönüş).

I A B C D H G F E ziyaret[] A T B T C T D T E T F T G T H T I F görülmedi yığında üstte çıktı

B'nin komşusu E zaten ziyaret edilmiş → atla.

I A B C D H G F E ziyaret[] A T B T C T D T E T F T G T H T I F görülmedi yığında üstte çıktı

B'nin gidilecek komşusu kalmadı → dfs(B) biter, çerçeve yığından çıkar (geri dönüş).

I A B C D H G F E ziyaret[] A T B T C T D T E T F T G T H T I F görülmedi yığında üstte çıktı

A'nın komşusu F zaten ziyaret edilmiş → atla.

I A B C D H G F E ziyaret[] A T B T C T D T E T F T G T H T I T görülmedi yığında üstte çıktı

A'nın komşusu I ziyaret edilmemiş → dfs(I) çağrılır: yeni çerçeve açılır, I işaretlenip yazdırılır.

I A B C D H G F E ziyaret[] A T B T C T D T E T F T G T H T I T görülmedi yığında üstte çıktı

I'nın komşusu A zaten ziyaret edilmiş → atla.

I A B C D H G F E ziyaret[] A T B T C T D T E T F T G T H T I T görülmedi yığında üstte çıktı

I'nın gidilecek komşusu kalmadı → dfs(I) biter, çerçeve yığından çıkar (geri dönüş).

I A B C D H G F E ziyaret[] A T B T C T D T E T F T G T H T I T görülmedi yığında üstte çıktı

dfs(A) biter, yığın boşalır. Sıra: A B C D G E F H I.

Gezinme (BFS / DFS) · Kodu adım adım çalıştır

Kod İzleme: dfsYigin(A)

void dfsYigin(int s) {
  boolean[] ziyaret = new boolean[n];
  Deque<Integer> yigin = new ArrayDeque<>();
  yigin.push(s);  ziyaret[s] = true;
  while (!yigin.isEmpty()) {
    int v = yigin.peek();
    Integer yeni = null;
    for (int u : komsu.get(v))
      if (!ziyaret[u]) { yeni = u; break; }
    if (yeni == null) yigin.pop(); // geri
    else { ziyaret[yeni] = true;
           yigin.push(yeni); }
  }
}
I A B C D H G F E yigin (alt → üst) (boş) ziyaret[] A F B F C F D F E F F F G F H F I F görülmedi yığında üstte çıktı

Başlangıç s = A. ziyaret tümü false, yığın boş.

I A B C D H G F E yigin (alt → üst) A ziyaret[] A T B F C F D F E F F F G F H F I F görülmedi yığında üstte çıktı

A yığına itilir ve işaretlenir. Yığının üstü = şu an bulunduğumuz düğüm.

I A B C D H G F E yigin (alt → üst) A B ziyaret[] A T B T C F D F E F F F G F H F I F görülmedi yığında üstte çıktı

peek = A; ilk ziyaret edilmemiş komşusu B (break) → işaretlenir ve yığına itilir.

I A B C D H G F E yigin (alt → üst) A B C ziyaret[] A T B T C T D F E F F F G F H F I F görülmedi yığında üstte çıktı

peek = B; ilk ziyaret edilmemiş komşusu C (break) → işaretlenir ve yığına itilir.

I A B C D H G F E yigin (alt → üst) A B C D ziyaret[] A T B T C T D T E F F F G F H F I F görülmedi yığında üstte çıktı

peek = C; ilk ziyaret edilmemiş komşusu D (break) → işaretlenir ve yığına itilir.

I A B C D H G F E yigin (alt → üst) A B C D G ziyaret[] A T B T C T D T E F F F G T H F I F görülmedi yığında üstte çıktı

peek = D; ilk ziyaret edilmemiş komşusu G (break) → işaretlenir ve yığına itilir.

I A B C D H G F E yigin (alt → üst) A B C D G E ziyaret[] A T B T C T D T E T F F G T H F I F görülmedi yığında üstte çıktı

peek = G; ilk ziyaret edilmemiş komşusu E (break) → işaretlenir ve yığına itilir.

I A B C D H G F E yigin (alt → üst) A B C D G ziyaret[] A T B T C T D T E T F F G T H F I F görülmedi yığında üstte çıktı

peek = E; ziyaret edilmemiş komşusu yok (yeni = null) → pop, geri dönülür.

I A B C D H G F E yigin (alt → üst) A B C D G F ziyaret[] A T B T C T D T E T F T G T H F I F görülmedi yığında üstte çıktı

peek = G; ilk ziyaret edilmemiş komşusu F (break) → işaretlenir ve yığına itilir.

I A B C D H G F E yigin (alt → üst) A B C D G ziyaret[] A T B T C T D T E T F T G T H F I F görülmedi yığında üstte çıktı

peek = F; ziyaret edilmemiş komşusu yok (yeni = null) → pop, geri dönülür.

I A B C D H G F E yigin (alt → üst) A B C D ziyaret[] A T B T C T D T E T F T G T H F I F görülmedi yığında üstte çıktı

peek = G; ziyaret edilmemiş komşusu yok (yeni = null) → pop, geri dönülür.

I A B C D H G F E yigin (alt → üst) A B C D H ziyaret[] A T B T C T D T E T F T G T H T I F görülmedi yığında üstte çıktı

peek = D; ilk ziyaret edilmemiş komşusu H (break) → işaretlenir ve yığına itilir.

I A B C D H G F E yigin (alt → üst) A B C D ziyaret[] A T B T C T D T E T F T G T H T I F görülmedi yığında üstte çıktı

peek = H; ziyaret edilmemiş komşusu yok (yeni = null) → pop, geri dönülür.

I A B C D H G F E yigin (alt → üst) A B C ziyaret[] A T B T C T D T E T F T G T H T I F görülmedi yığında üstte çıktı

peek = D; ziyaret edilmemiş komşusu yok (yeni = null) → pop, geri dönülür.

I A B C D H G F E yigin (alt → üst) A B ziyaret[] A T B T C T D T E T F T G T H T I F görülmedi yığında üstte çıktı

peek = C; ziyaret edilmemiş komşusu yok (yeni = null) → pop, geri dönülür.

I A B C D H G F E yigin (alt → üst) A ziyaret[] A T B T C T D T E T F T G T H T I F görülmedi yığında üstte çıktı

peek = B; ziyaret edilmemiş komşusu yok (yeni = null) → pop, geri dönülür.

I A B C D H G F E yigin (alt → üst) A I ziyaret[] A T B T C T D T E T F T G T H T I T görülmedi yığında üstte çıktı

peek = A; ilk ziyaret edilmemiş komşusu I (break) → işaretlenir ve yığına itilir.

I A B C D H G F E yigin (alt → üst) A ziyaret[] A T B T C T D T E T F T G T H T I T görülmedi yığında üstte çıktı

peek = I; ziyaret edilmemiş komşusu yok (yeni = null) → pop, geri dönülür.

I A B C D H G F E yigin (alt → üst) (boş) ziyaret[] A T B T C T D T E T F T G T H T I T görülmedi yığında üstte çıktı

peek = A; ziyaret edilmemiş komşusu yok (yeni = null) → pop, geri dönülür. Yığın boş: bitti. Ziyaret sırası özyinelemeli sürümle aynı.

Gezinme (BFS / DFS)

BFS ve DFS Karşılaştırması

BFSDFS
Yardımcı yapıKuyruk (FIFO)Yığın (LIFO) / özyineleme
Zaman (komşuluk listesi)O(n + m)O(n + m)
Ek bellekO(n): en geniş seviye kuyruktaO(n): en uzun yol yığında
En kısa yol?Evet (ağırlıksız çizgede)Hayır
Tipik kullanımen az adım, seviye bulmadöngü tespiti, bileşenler, labirent
Neden O(n + m)? Her düğüm bir kez işlenir ve tüm komşuluk kayıtları taranır. Yönsüz çizgede her kenar iki listede görünür; 2m yine O(m)'dir.

Sıralar, komşuların alfabetik sırayla gezildiği varsayımıyla elde edildi; komşu sırası değişirse ziyaret sırası da değişir.

Gezinme (BFS / DFS) · Kodu adım adım çalıştır

Kod İzleme: DFS ile bileşenleri numaralama

0 1 2 3 4 5 v bil -1 0 -1 1 -1 2 -1 3 -1 4 -1 5

Tüm düğümler −1 (henüz hiçbir bileşene atanmadı).

0 1 2 3 4 5 v bil -1 0 -1 1 -1 2 -1 3 -1 4 -1 5

Bileşen sayacı say = 0.

0 1 2 3 4 5 v bil -1 0 -1 1 -1 2 -1 3 -1 4 -1 5

bil[0] = −1: yeni bileşen. say++ 0 verir, say = 1 olur; dfs(0, 0) çağrılır.

0 1 2 3 4 5 v bil 0 0 -1 1 -1 2 -1 3 -1 4 -1 5

bil[0] = 0: 0, 0 numaralı bileşene boyandı.

0 1 2 3 4 5 v bil 0 0 0 1 -1 2 -1 3 -1 4 -1 5

bil[1] = 0: 1, 0 numaralı bileşene boyandı.

0 1 2 3 4 5 v bil 0 0 0 1 -1 2 -1 3 -1 4 -1 5

Komşu 0 zaten boyalı (bil = 0) → atla. Her kenara iki kez bakılır: O(n + m).

0 1 2 3 4 5 v bil 0 0 0 1 0 2 -1 3 -1 4 -1 5

bil[2] = 0: 2, 0 numaralı bileşene boyandı.

0 1 2 3 4 5 v bil 0 0 0 1 0 2 -1 3 -1 4 -1 5

Komşu 0 zaten boyalı (bil = 0) → atla. Her kenara iki kez bakılır: O(n + m).

0 1 2 3 4 5 v bil 0 0 0 1 0 2 -1 3 -1 4 -1 5

bil[1] = 0: 1 önceki bir DFS'te zaten boyandı → atla.

0 1 2 3 4 5 v bil 0 0 0 1 0 2 -1 3 -1 4 -1 5

bil[2] = 0: 2 önceki bir DFS'te zaten boyandı → atla.

0 1 2 3 4 5 v bil 0 0 0 1 0 2 -1 3 -1 4 -1 5

bil[3] = −1: yeni bileşen. say++ 1 verir, say = 2 olur; dfs(3, 1) çağrılır.

0 1 2 3 4 5 v bil 0 0 0 1 0 2 1 3 -1 4 -1 5

bil[3] = 1: 3, 1 numaralı bileşene boyandı.

0 1 2 3 4 5 v bil 0 0 0 1 0 2 1 3 1 4 -1 5

bil[4] = 1: 4, 1 numaralı bileşene boyandı.

0 1 2 3 4 5 v bil 0 0 0 1 0 2 1 3 1 4 -1 5

Komşu 3 zaten boyalı (bil = 1) → atla. Her kenara iki kez bakılır: O(n + m).

0 1 2 3 4 5 v bil 0 0 0 1 0 2 1 3 1 4 -1 5

bil[4] = 1: 4 önceki bir DFS'te zaten boyandı → atla.

0 1 2 3 4 5 v bil 0 0 0 1 0 2 1 3 1 4 -1 5

bil[5] = −1: yeni bileşen. say++ 2 verir, say = 3 olur; dfs(5, 2) çağrılır.

0 1 2 3 4 5 v bil 0 0 0 1 0 2 1 3 1 4 2 5

bil[5] = 2: 5, 2 numaralı bileşene boyandı.

0 1 2 3 4 5 v bil 0 0 0 1 0 2 1 3 1 4 2 5

3 bileşen: {0, 1, 2}, {3, 4}, {5}. Aynı bil = aynı bileşen; bil[u] == bil[v] sorgusu O(1).

int bilesenler(int[] bil) {
  Arrays.fill(bil, -1);
  int say = 0;
  for (int s = 0; s < n; s++)
    if (bil[s] == -1) dfs(s, say++, bil);
  return say;
}
void dfs(int v, int c, int[] bil) {
  bil[v] = c;
  for (int u : komsu.get(v))
    if (bil[u] == -1) dfs(u, c, bil);
}

Gezinme (BFS / DFS)

İki Parçalı (Bipartite) Çizge Testi

  • İki parçalı (bipartite): düğümler iki gruba ayrılır, her kenar gruplar arasında.
  • Test = BFS ile 2-renkleme: komşuya zıt renk ver; aynı renkli iki komşu → değil.
  • Eşdeğer: tek uzunlukta döngü yok.
0 1 2 3 4 5 0 1 2 iki parçalı ✓ (çift döngüler) üçgen ✗: 0 ve 2 aynı renk
// renk[] = -1 ile başlar; s'den BFS
renk[s] = 0;  q.add(s);
while (!q.isEmpty()) {
  int w = q.poll();
  for (int u : komsu.get(w))
    if (renk[u] == -1) {
      renk[u] = 1 - renk[w];  q.add(u);
    } else if (renk[u] == renk[w]) return false;
}
return true;

BFS ile aynı maliyet: O(n + m). Kullanım: öğrenci–proje eşleştirme, iki vardiyalı çizelgeleme, çakışmasız gruplama.

Gezinme (BFS / DFS)

Topolojik Sıralama: Yalnızca DAG

  • Bir yönlü çizgenin düğümlerini, her u → v kenarında u, v'den önce gelecek biçimde sıralar.
  • Yalnızca yönlü döngüsüz çizgelerde (DAG) mümkündür.
  • Sonuç tek olmak zorunda değildir; aynı anda seçilebilen birden çok giriş derecesi 0 düğüm olabilir.
  • Kullanım: ders ön koşulları, görev bağımlılıkları, derleme ve iş akışı planlama.
Çizgede döngü varsa hiçbir topolojik sıra yoktur: döngüdeki her görev başka bir görevin önce yapılmasını bekler.
Kahn(G):
  q = girişDerecesi 0 olan düğümler
  sonuc = []
  while q boş değil:
    u = q'dan çıkar
    sonuc'a u ekle
    for u'dan çıkan her (u, v):
      girişDerecesi[v]--
      if girişDerecesi[v] == 0:
        q'ya v ekle
  if sonuc.size < n:
    döngü var
  return sonuc
ZamanO(n + m)
AlternatifDFS bitiş zamanlarını ters çevirmek; geri kenar bulunursa döngü vardır.

Gezinme (BFS / DFS) · Kodu adım adım çalıştır

Kod İzleme: Topolojik Sıralama (Kahn)

List<Integer> kahn(List<List<Integer>> adj) {
  int n = adj.size();
  int[] giris = new int[n];
  for (List<Integer> l : adj)
    for (int v : l) giris[v]++;
  Queue<Integer> q = new ArrayDeque<>();
  for (int v = 0; v < n; v++)
    if (giris[v] == 0) q.add(v);
  List<Integer> sonuc = new ArrayList<>();
  while (!q.isEmpty()) {
    int u = q.poll();
    sonuc.add(u);
    for (int v : adj.get(u))
      if (--giris[v] == 0) q.add(v);
  }
  return sonuc;  // boyut < n → döngü
}
1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 0 0 0 0 0 0 q (boş) sonuc [ ]

Ders ön koşulu örneği: 6 düğüm, 7 yönlü kenar (u → v: u, v'den önce). giris[] sıfırlarla başlar.

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 0 0 0 1 0 0 q (boş) sonuc [ ]

0'dan çıkan kenarlar 0→3: hedeflerin giriş derecesi birer artar.

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 0 0 0 2 1 0 q (boş) sonuc [ ]

1'den çıkan kenarlar 1→3, 1→4: hedeflerin giriş derecesi birer artar.

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 1 0 0 2 2 0 q (boş) sonuc [ ]

2'den çıkan kenarlar 2→0, 2→4: hedeflerin giriş derecesi birer artar.

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 1 0 0 2 2 1 q (boş) sonuc [ ]

3'ten çıkan kenarlar 3→5: hedeflerin giriş derecesi birer artar.

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 1 0 0 2 2 2 q (boş) sonuc [ ]

4'ten çıkan kenarlar 4→5: hedeflerin giriş derecesi birer artar.

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 1 0 0 2 2 2 q 1 2 sonuc [ ]

Giriş derecesi 0 olanlar (1, 2) hiçbir şeye bağımlı değil → kuyruğa. (5'in listesi boş olduğundan sayma turu bir şey değiştirmedi.)

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 1 0 0 2 2 2 q 2 sonuc 1

1 kuyruktan çıkar ve sonuca eklenir: ön koşullarının hepsi zaten sonuçta.

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 1 0 0 1 2 2 q 2 sonuc 1

1→3 silinmiş sayılır: giris[3] = 1; 3 hâlâ başka bir ön koşul bekliyor.

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 1 0 0 1 1 2 q 2 sonuc 1

1→4 silinmiş sayılır: giris[4] = 1; 4 hâlâ başka bir ön koşul bekliyor.

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 1 0 0 1 1 2 q (boş) sonuc 1 2

2 kuyruktan çıkar ve sonuca eklenir: ön koşullarının hepsi zaten sonuçta.

Gezinme (BFS / DFS) · Kodu adım adım çalıştır

Kod İzleme: Topolojik Sıralama (Kahn) (devam)

List<Integer> kahn(List<List<Integer>> adj) {
  int n = adj.size();
  int[] giris = new int[n];
  for (List<Integer> l : adj)
    for (int v : l) giris[v]++;
  Queue<Integer> q = new ArrayDeque<>();
  for (int v = 0; v < n; v++)
    if (giris[v] == 0) q.add(v);
  List<Integer> sonuc = new ArrayList<>();
  while (!q.isEmpty()) {
    int u = q.poll();
    sonuc.add(u);
    for (int v : adj.get(u))
      if (--giris[v] == 0) q.add(v);
  }
  return sonuc;  // boyut < n → döngü
}
1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 0 0 0 1 1 2 q 0 sonuc 1 2

2→0 silinmiş sayılır: giris[0] = 0 → 0 artık hazır, kuyruğa eklenir.

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 0 0 0 1 0 2 q 0 4 sonuc 1 2

2→4 silinmiş sayılır: giris[4] = 0 → 4 artık hazır, kuyruğa eklenir.

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 0 0 0 1 0 2 q 4 sonuc 1 2 0

0 kuyruktan çıkar ve sonuca eklenir: ön koşullarının hepsi zaten sonuçta.

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 0 0 0 0 0 2 q 4 3 sonuc 1 2 0

0→3 silinmiş sayılır: giris[3] = 0 → 3 artık hazır, kuyruğa eklenir.

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 0 0 0 0 0 2 q 3 sonuc 1 2 0 4

4 kuyruktan çıkar ve sonuca eklenir: ön koşullarının hepsi zaten sonuçta.

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 0 0 0 0 0 1 q 3 sonuc 1 2 0 4

4→5 silinmiş sayılır: giris[5] = 1; 5 hâlâ başka bir ön koşul bekliyor.

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 0 0 0 0 0 1 q (boş) sonuc 1 2 0 4 3

3 kuyruktan çıkar ve sonuca eklenir: ön koşullarının hepsi zaten sonuçta.

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 0 0 0 0 0 0 q 5 sonuc 1 2 0 4 3

3→5 silinmiş sayılır: giris[5] = 0 → 5 artık hazır, kuyruğa eklenir.

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 0 0 0 0 0 0 q (boş) sonuc 1 2 0 4 3 5

5 kuyruktan çıkar ve sonuca eklenir: ön koşullarının hepsi zaten sonuçta.

1 2 0 3 4 5 giris[] (giriş derecesi) 0 1 2 3 4 5 giris 0 0 0 0 0 0 q (boş) sonuc 1 2 0 4 3 5

Kuyruk boş; sonuç 1 2 0 4 3 5 ve boyutu 6 = n → döngü yok. Her kenar bir kez azaltıldı: O(n + m).

Gezinme (BFS / DFS) · Kodu adım adım çalıştır

Kod İzleme: yönlü çizgede döngü (3 renkli DFS)

0 1 2 3 4 v renk 1 0 0 1 0 2 0 3 0 4 0 beyaz · 1 gri · 2 siyah

renk[0] = 1 (gri): 0 şu anki DFS yolunda.

0 1 2 3 4 v renk 1 0 0 1 0 2 0 3 0 4 0 beyaz · 1 gri · 2 siyah

Kenar 0 → 1: 1 beyaz → özyinelemeli çağrı.

0 1 2 3 4 v renk 1 0 1 1 0 2 0 3 0 4 0 beyaz · 1 gri · 2 siyah

renk[1] = 1 (gri): 1 şu anki DFS yolunda.

0 1 2 3 4 v renk 1 0 1 1 0 2 0 3 0 4 0 beyaz · 1 gri · 2 siyah

Kenar 1 → 2: 2 beyaz → özyinelemeli çağrı.

0 1 2 3 4 v renk 1 0 1 1 1 2 0 3 0 4 0 beyaz · 1 gri · 2 siyah

renk[2] = 1 (gri): 2 şu anki DFS yolunda.

0 1 2 3 4 v renk 1 0 1 1 2 2 0 3 0 4 0 beyaz · 1 gri · 2 siyah

2'nin çıkan kenarı yok: renk[2] = 2 (siyah), false döner; yığından çıkar.

0 1 2 3 4 v renk 1 0 2 1 2 2 0 3 0 4 0 beyaz · 1 gri · 2 siyah

1'in tüm komşuları bitti: renk[1] = 2 (siyah), false döner; yığından çıkar.

0 1 2 3 4 v renk 1 0 2 1 2 2 0 3 0 4 0 beyaz · 1 gri · 2 siyah

Kenar 0 → 3: 3 beyaz → özyinelemeli çağrı.

0 1 2 3 4 v renk 1 0 2 1 2 2 1 3 0 4 0 beyaz · 1 gri · 2 siyah

renk[3] = 1 (gri): 3 şu anki DFS yolunda.

0 1 2 3 4 v renk 1 0 2 1 2 2 1 3 0 4 0 beyaz · 1 gri · 2 siyah

Kenar 3 → 2: 2 siyah (bitmiş). Döngü değil: 2'den geri 3'e yol yok. Sadece gri düğüm döngü demektir.

0 1 2 3 4 v renk 1 0 2 1 2 2 1 3 0 4 0 beyaz · 1 gri · 2 siyah

Kenar 3 → 4: 4 beyaz → özyinelemeli çağrı.

0 1 2 3 4 v renk 1 0 2 1 2 2 1 3 1 4 0 beyaz · 1 gri · 2 siyah

renk[4] = 1 (gri): 4 şu anki DFS yolunda.

0 1 2 3 4 v renk 1 0 2 1 2 2 1 3 1 4 0 beyaz · 1 gri · 2 siyah geri kenar → DÖNGÜ

Kenar 4 → 0: 0 gri, yani yolda! Bu bir geri kenar → döngü 0 → 3 → 4 → 0 bulundu.

0 1 2 3 4 v renk 1 0 2 1 2 2 1 3 1 4 0 beyaz · 1 gri · 2 siyah geri kenar → DÖNGÜ

Alttaki çağrı true döndü → 3 de true döndürür.

0 1 2 3 4 v renk 1 0 2 1 2 2 1 3 1 4 0 beyaz · 1 gri · 2 siyah geri kenar → DÖNGÜ

Alttaki çağrı true döndü → 0 da true döndürür.

// renk: 0 beyaz, 1 gri (yolda), 2 siyah
boolean donguVar(int v, int[] renk) {
  renk[v] = 1;
  for (int u : komsu.get(v)) {
    if (renk[u] == 1) return true;  // geri kenar
    if (renk[u] == 0 && donguVar(u, renk))
      return true;
  }
  renk[v] = 2;
  return false;
}

En Kısa Yol

Ağırlıksız En Kısa Yol Problemi

  • Kaynak düğümden diğer tüm düğümlere olan en kısa yolları bulur (tek kaynaklı en kısa yol).
  • Her kenarın aynı ağırlığa (1) sahip olduğu varsayılır: yol uzunluğu = kenar sayısı.
  • Çözüm: BFS. Seviye k'daki düğümün uzaklığı tam olarak k'dır.
1 2 5 3 8 4 6 7 0 1 2 1 2 1 2 3

Kaynak 1; düğümlerin yanındaki sayı 1'e uzaklık

7'ye iki en kısa yol var: 1 → 4 → 6 → 7 ve 1 → 3 → 8 → 7 (ikisi de 3 kenar). BFS bunlardan birini bulur; uzunluk her durumda 3'tür.

En Kısa Yol

Ağırlıksız En Kısa Yol Algoritması

Sözde kod
mesafe[tüm v] = ∞
mesafe[s] = 0
kuyruk.ekle(s)
while kuyruk boş değil:
  w = kuyruk.çıkar()
  for w'nin her komşusu u:
    if mesafe[u] == ∞:
      mesafe[u] = mesafe[w] + 1
      kuyruk.ekle(u)
return mesafe

"mesafe = ∞" aynı zamanda "ziyaret edilmedi" demektir; ayrı bir dizi gerekmez. Java'da cizge: düğüm → komşu listesi (Map<Integer, List<Integer>>), çünkü düğümler 1'den başlayarak numaralanmış.

Java · O(n + m)
Map<Integer, Integer> enKisaYol(int s) {
  final int INF = Integer.MAX_VALUE;  // ∞
  Map<Integer, Integer> mesafe =
      new HashMap<>();
  for (int v : cizge.keySet())
    mesafe.put(v, INF);
  mesafe.put(s, 0);
  Queue<Integer> q = new ArrayDeque<>();
  q.offer(s);
  while (!q.isEmpty()) {
    int w = q.poll();
    for (int u : cizge.get(w))
      if (mesafe.get(u) == INF) {
        mesafe.put(u, mesafe.get(w) + 1);
        q.offer(u);
      }
  }
  return mesafe;
}

En Kısa Yol · Kodu adım adım çalıştır

Kod İzleme: enKisaYol(1)

Map<Integer, Integer> enKisaYol(int s) {
  final int INF = Integer.MAX_VALUE;  // ∞
  Map<Integer, Integer> mesafe =
      new HashMap<>();
  for (int v : cizge.keySet())
    mesafe.put(v, INF);
  mesafe.put(s, 0);
  Queue<Integer> q = new ArrayDeque<>();
  q.offer(s);
  while (!q.isEmpty()) {
    int w = q.poll();
    for (int u : cizge.get(w))
      if (mesafe.get(u) == INF) {
        mesafe.put(u, mesafe.get(w) + 1);
        q.offer(u);
      }
  }
  return mesafe;
}
1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe ∞ ∞ ∞ ∞ ∞ ∞ ∞ ∞ q (boş)

Kaynak s = 1. Tüm mesafeler INF (∞): "henüz ulaşılmadı" = "ziyaret edilmedi".

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 ∞ ∞ ∞ ∞ ∞ ∞ ∞ q 1

mesafe[1] = 0 ve 1 kuyruğa girer.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 ∞ ∞ ∞ ∞ ∞ ∞ ∞ q (boş)

1 çıkarılır; mesafe[1] = 0. Komşuları 2, 3, 4 incelenir.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 ∞ ∞ ∞ ∞ ∞ ∞ q 2

mesafe[2] = INF → mesafe[2] = 0 + 1 = 1, 2 kuyruğa eklenir.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 ∞ ∞ ∞ ∞ ∞ q 2 3

mesafe[3] = INF → mesafe[3] = 0 + 1 = 1, 3 kuyruğa eklenir.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 ∞ ∞ ∞ ∞ q 2 3 4

mesafe[4] = INF → mesafe[4] = 0 + 1 = 1, 4 kuyruğa eklenir.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 ∞ ∞ ∞ ∞ q 3 4

2 çıkarılır; mesafe[2] = 1. Komşuları 1, 5 incelenir.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 ∞ ∞ ∞ ∞ q 3 4

1: mesafesi zaten belli (0) → değişmez. BFS'de ilk bulunan mesafe en kısadır.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 2 ∞ ∞ ∞ q 3 4 5

mesafe[5] = INF → mesafe[5] = 1 + 1 = 2, 5 kuyruğa eklenir.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 2 ∞ ∞ ∞ q 4 5

3 çıkarılır; mesafe[3] = 1. Komşuları 1, 8 incelenir.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 2 ∞ ∞ ∞ q 4 5

1: mesafesi zaten belli (0) → değişmez. BFS'de ilk bulunan mesafe en kısadır.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 2 ∞ ∞ 2 q 4 5 8

mesafe[8] = INF → mesafe[8] = 1 + 1 = 2, 8 kuyruğa eklenir.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 2 ∞ ∞ 2 q 5 8

4 çıkarılır; mesafe[4] = 1. Komşuları 1, 6 incelenir.

En Kısa Yol · Kodu adım adım çalıştır

Kod İzleme: enKisaYol(1) (devam)

Map<Integer, Integer> enKisaYol(int s) {
  final int INF = Integer.MAX_VALUE;  // ∞
  Map<Integer, Integer> mesafe =
      new HashMap<>();
  for (int v : cizge.keySet())
    mesafe.put(v, INF);
  mesafe.put(s, 0);
  Queue<Integer> q = new ArrayDeque<>();
  q.offer(s);
  while (!q.isEmpty()) {
    int w = q.poll();
    for (int u : cizge.get(w))
      if (mesafe.get(u) == INF) {
        mesafe.put(u, mesafe.get(w) + 1);
        q.offer(u);
      }
  }
  return mesafe;
}
1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 2 ∞ ∞ 2 q 5 8

1: mesafesi zaten belli (0) → değişmez. BFS'de ilk bulunan mesafe en kısadır.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 2 2 ∞ 2 q 5 8 6

mesafe[6] = INF → mesafe[6] = 1 + 1 = 2, 6 kuyruğa eklenir.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 2 2 ∞ 2 q 8 6

5 çıkarılır; mesafe[5] = 2. Komşuları 2, 8 incelenir.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 2 2 ∞ 2 q 8 6

2, 8: mesafesi zaten belli (1, 2) → değişmez. BFS'de ilk bulunan mesafe en kısadır.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 2 2 ∞ 2 q 6

8 çıkarılır; mesafe[8] = 2. Komşuları 3, 5, 7 incelenir.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 2 2 ∞ 2 q 6

3, 5: mesafesi zaten belli (1, 2) → değişmez. BFS'de ilk bulunan mesafe en kısadır.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 2 2 3 2 q 6 7

mesafe[7] = INF → mesafe[7] = 2 + 1 = 3, 7 kuyruğa eklenir.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 2 2 3 2 q 7

6 çıkarılır; mesafe[6] = 2. Komşuları 4, 7 incelenir.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 2 2 3 2 q 7

4, 7: mesafesi zaten belli (1, 3) → değişmez. BFS'de ilk bulunan mesafe en kısadır.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 2 2 3 2 q (boş)

7 çıkarılır; mesafe[7] = 3. Komşuları 6, 8 incelenir.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 2 2 3 2 q (boş)

6, 8: mesafesi zaten belli (2, 2) → değişmez. BFS'de ilk bulunan mesafe en kısadır.

1 2 5 3 8 4 6 7 1 2 3 4 5 6 7 8 mesafe 0 1 1 1 2 2 3 2 q (boş)

Kuyruk boş → return mesafe. 7'ye uzaklık 3 (1 → 3 → 8 → 7 bulundu; 1 → 4 → 6 → 7 de 3 kenar). O(n + m).

En Kısa Yol

Ağırlıklı En Kısa Yol Problemi

  • Kaynak düğümden diğer tüm düğümlere olan en kısa yolları bulur.
  • Her kenarın farklı bir ağırlığı olabilir: uzaklık, süre, maliyet…
  • Yol uzunluğu = kenar ağırlıklarının toplamı.
4 2 5 10 3 4 11 A B D C E F

A'dan F'ye en kısa yol: A → C → E → D → F = 2 + 3 + 4 + 11 = 20

BFS burada yetmezEn az kenarlı yol A → B → D → F (3 kenar) ama uzunluğu 4 + 10 + 11 = 25.
Çözüm: Dijkstra algoritmasıEdsger W. Dijkstra, 1956. Ağırlıklar negatif olmamalıdır.

En Kısa Yol

Dijkstra Algoritması: Fikir ve Sözde Kod

  • Kesinleşmemiş düğümlerden mesafesi en küçük olanı seç.
  • Komşuların mesafesini gevşetme ile güncelle.
  • Seçim için öncelikli kuyruk, yolu kurmak için önceki[] kullan.
Dijkstra(G, s):
  for her düğüm v:
    mesafe[v] = ∞
    önceki[v] = tanımsız
  mesafe[s] = 0
  Q = tüm düğümler  // öncelikli kuyruk
  while Q boş değil:
    u = Q.çıkar()   // en küçük mesafe[u]
    for u'nun Q'daki her komşusu v:
      alt = mesafe[u] + ağırlık(u, v)
      if alt < mesafe[v]:
        mesafe[v] = alt
        önceki[v] = u
        // Q'da v'nin önceliğini azalt

En Kısa Yol

Dijkstra Algoritması: Java

long[] dijkstra(List<List<int[]>> adj, int s, int[] onceki) { // ağırlıklar ≥ 0
    long[] d = new long[adj.size()];
    Arrays.fill(d, Long.MAX_VALUE);  d[s] = 0;  Arrays.fill(onceki, -1);
    PriorityQueue<long[]> pq =                     // {düğüm, mesafe}
        new PriorityQueue<>((a, b) -> Long.compare(a[1], b[1]));
    pq.add(new long[]{s, 0});
    while (!pq.isEmpty()) {
        long[] e = pq.poll();  int u = (int) e[0];
        if (e[1] > d[u]) continue;                   // bayat kayıt: atla
        for (int[] k : adj.get(u)) {
            int v = k[0];  long alt = d[u] + k[1];
            if (alt < d[v]) { d[v] = alt; onceki[v] = u; pq.add(new long[]{v, alt}); }
        }
    }
    return d;
}
Öncelik = mesafe (düğüm numarası değil). Java'nın PriorityQueue'sunda "önceliği azalt" yok: yeni kayıt eklenir, eskisi çıkınca bayat olarak atlanır. onceki[v] = u en kısa yol ağacını tutar; yol hedeften geriye izlenir.

En Kısa Yol · Kodu adım adım çalıştır

Kod İzleme: dijkstra(adj, A)

// d[] = ∞, d[s] = 0, onceki[] = -1
pq.add(new long[]{s, 0});
while (!pq.isEmpty()) {
  long[] e = pq.poll();
  int u = (int) e[0];
  if (e[1] > d[u]) continue;  // bayat
  for (int[] k : adj.get(u)) {
    int v = k[0];
    long alt = d[u] + k[1];
    if (alt < d[v]) {
      d[v] = alt;
      onceki[v] = u;
      pq.add(new long[]{v, alt});
    }
  }
}
3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 ∞ ∞ ∞ ∞ ∞ ∞ ∞ ∞ onceki – – – – – – – – – pq (mesafeye göre sıralı gösterim; soluk = bayat) A,0

Kaynak A: d[A] = 0, diğerleri ∞. Kuyruğa {A, 0} eklenir. Öncelik = mesafe.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 ∞ ∞ ∞ ∞ ∞ ∞ ∞ ∞ onceki – – – – – – – – – pq (mesafeye göre sıralı gösterim; soluk = bayat) (boş)

En küçük kayıt {A, 0} çıkar; 0 = d[A] (güncel) → A kesinleşir. Komşuları B, F, I gevşetilir.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 ∞ ∞ ∞ ∞ ∞ ∞ ∞ onceki – A – – – – – – – pq (mesafeye göre sıralı gösterim; soluk = bayat) B,4

v = B: alt = 0 + 4 = 4 < ∞ → d[B] = 4, onceki[B] = A, {B, 4} kuyruğa.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 ∞ ∞ ∞ 7 ∞ ∞ ∞ onceki – A – – – A – – – pq (mesafeye göre sıralı gösterim; soluk = bayat) B,4 F,7

v = F: alt = 0 + 7 = 7 < ∞ → d[F] = 7, onceki[F] = A, {F, 7} kuyruğa.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 ∞ ∞ ∞ 7 ∞ ∞ 3 onceki – A – – – A – – A pq (mesafeye göre sıralı gösterim; soluk = bayat) I,3 B,4 F,7

v = I: alt = 0 + 3 = 3 < ∞ → d[I] = 3, onceki[I] = A, {I, 3} kuyruğa.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 ∞ ∞ ∞ 7 ∞ ∞ 3 onceki – A – – – A – – A pq (mesafeye göre sıralı gösterim; soluk = bayat) B,4 F,7

En küçük kayıt {I, 3} çıkar; 3 = d[I] (güncel) → I kesinleşir. Komşusu A gevşetilir.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 ∞ ∞ ∞ 7 ∞ ∞ 3 onceki – A – – – A – – A pq (mesafeye göre sıralı gösterim; soluk = bayat) B,4 F,7

v = A: alt = 6 ≥ d[A] = 0 → güncelleme yok.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 ∞ ∞ ∞ 7 ∞ ∞ 3 onceki – A – – – A – – A pq (mesafeye göre sıralı gösterim; soluk = bayat) F,7

En küçük kayıt {B, 4} çıkar; 4 = d[B] (güncel) → B kesinleşir. Komşuları A, C, E gevşetilir.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 ∞ ∞ ∞ 7 ∞ ∞ 3 onceki – A – – – A – – A pq (mesafeye göre sıralı gösterim; soluk = bayat) F,7

v = A: alt = 8 ≥ d[A] = 0 → güncelleme yok.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 ∞ ∞ 7 ∞ ∞ 3 onceki – A B – – A – – A pq (mesafeye göre sıralı gösterim; soluk = bayat) C,5 F,7

v = C: alt = 4 + 1 = 5 < ∞ → d[C] = 5, onceki[C] = B, {C, 5} kuyruğa.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 ∞ 6 7 ∞ ∞ 3 onceki – A B – B A – – A pq (mesafeye göre sıralı gösterim; soluk = bayat) C,5 E,6 F,7

v = E: alt = 4 + 2 = 6 < ∞ → d[E] = 6, onceki[E] = B, {E, 6} kuyruğa.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 ∞ 6 7 ∞ ∞ 3 onceki – A B – B A – – A pq (mesafeye göre sıralı gösterim; soluk = bayat) E,6 F,7

En küçük kayıt {C, 5} çıkar; 5 = d[C] (güncel) → C kesinleşir. Komşuları B, D, E gevşetilir.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 ∞ 6 7 ∞ ∞ 3 onceki – A B – B A – – A pq (mesafeye göre sıralı gösterim; soluk = bayat) E,6 F,7

v = B: alt = 6 ≥ d[B] = 4 → güncelleme yok.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 12 6 7 ∞ ∞ 3 onceki – A B C B A – – A pq (mesafeye göre sıralı gösterim; soluk = bayat) E,6 F,7 D,12

v = D: alt = 5 + 7 = 12 < ∞ → d[D] = 12, onceki[D] = C, {D, 12} kuyruğa.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 12 6 7 ∞ ∞ 3 onceki – A B C B A – – A pq (mesafeye göre sıralı gösterim; soluk = bayat) E,6 F,7 D,12

v = E: alt = 8 ≥ d[E] = 6 → güncelleme yok.

En Kısa Yol · Kodu adım adım çalıştır

Kod İzleme: dijkstra(adj, A) (devam)

// d[] = ∞, d[s] = 0, onceki[] = -1
pq.add(new long[]{s, 0});
while (!pq.isEmpty()) {
  long[] e = pq.poll();
  int u = (int) e[0];
  if (e[1] > d[u]) continue;  // bayat
  for (int[] k : adj.get(u)) {
    int v = k[0];
    long alt = d[u] + k[1];
    if (alt < d[v]) {
      d[v] = alt;
      onceki[v] = u;
      pq.add(new long[]{v, alt});
    }
  }
}
3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 12 6 7 ∞ ∞ 3 onceki – A B C B A – – A pq (mesafeye göre sıralı gösterim; soluk = bayat) F,7 D,12

En küçük kayıt {E, 6} çıkar; 6 = d[E] (güncel) → E kesinleşir. Komşuları B, C, G gevşetilir.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 12 6 7 ∞ ∞ 3 onceki – A B C B A – – A pq (mesafeye göre sıralı gösterim; soluk = bayat) F,7 D,12

v = B: alt = 8 ≥ d[B] = 4; v = C: alt = 9 ≥ d[C] = 5 → güncelleme yok.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 12 6 7 8 ∞ 3 onceki – A B C B A E – A pq (mesafeye göre sıralı gösterim; soluk = bayat) F,7 G,8 D,12

v = G: alt = 6 + 2 = 8 < ∞ → d[G] = 8, onceki[G] = E, {G, 8} kuyruğa.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 12 6 7 8 ∞ 3 onceki – A B C B A E – A pq (mesafeye göre sıralı gösterim; soluk = bayat) G,8 D,12

En küçük kayıt {F, 7} çıkar; 7 = d[F] (güncel) → F kesinleşir. Komşuları A, G gevşetilir.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 12 6 7 8 ∞ 3 onceki – A B C B A E – A pq (mesafeye göre sıralı gösterim; soluk = bayat) G,8 D,12

v = A: alt = 14 ≥ d[A] = 0; v = G: alt = 9 ≥ d[G] = 8 → güncelleme yok.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 12 6 7 8 ∞ 3 onceki – A B C B A E – A pq (mesafeye göre sıralı gösterim; soluk = bayat) D,12

En küçük kayıt {G, 8} çıkar; 8 = d[G] (güncel) → G kesinleşir. Komşuları D, E, F gevşetilir.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 11 6 7 8 ∞ 3 onceki – A B G B A E – A pq (mesafeye göre sıralı gösterim; soluk = bayat) D,11 D,12

v = D: alt = 8 + 3 = 11 < 12 → d[D] = 11, onceki[D] = G, {D, 11} kuyruğa. Eski {D, 12} kaydı kuyrukta bayat kalır.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 11 6 7 8 ∞ 3 onceki – A B G B A E – A pq (mesafeye göre sıralı gösterim; soluk = bayat) D,11 D,12

v = E: alt = 10 ≥ d[E] = 6; v = F: alt = 10 ≥ d[F] = 7 → güncelleme yok.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 11 6 7 8 ∞ 3 onceki – A B G B A E – A pq (mesafeye göre sıralı gösterim; soluk = bayat) D,12

En küçük kayıt {D, 11} çıkar; 11 = d[D] (güncel) → D kesinleşir. Komşuları C, G, H gevşetilir.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 11 6 7 8 ∞ 3 onceki – A B G B A E – A pq (mesafeye göre sıralı gösterim; soluk = bayat) D,12

v = C: alt = 18 ≥ d[C] = 5; v = G: alt = 14 ≥ d[G] = 8 → güncelleme yok.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 11 6 7 8 16 3 onceki – A B G B A E D A pq (mesafeye göre sıralı gösterim; soluk = bayat) D,12 H,16

v = H: alt = 11 + 5 = 16 < ∞ → d[H] = 16, onceki[H] = D, {H, 16} kuyruğa.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 11 6 7 8 16 3 onceki – A B G B A E D A pq (mesafeye göre sıralı gösterim; soluk = bayat) H,16

{D, 12} çıktı ama d[D] = 11 < 12: bayat kayıt (daha iyi yol sonradan bulundu) → continue, atlanır.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 11 6 7 8 16 3 onceki – A B G B A E D A pq (mesafeye göre sıralı gösterim; soluk = bayat) (boş)

En küçük kayıt {H, 16} çıkar; 16 = d[H] (güncel) → H kesinleşir. Komşusu D gevşetilir.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 11 6 7 8 16 3 onceki – A B G B A E D A pq (mesafeye göre sıralı gösterim; soluk = bayat) (boş)

v = D: alt = 21 ≥ d[D] = 11 → güncelleme yok.

3 4 7 1 2 3 7 2 2 3 5 I A B C D H G F E A B C D E F G H I d[] 0 4 5 11 6 7 8 16 3 onceki – A B G B A E D A pq (mesafeye göre sıralı gösterim; soluk = bayat) (boş)

Kuyruk boş → bitti. onceki[] geri izlenir: H ← D ← G ← E ← B ← A. En kısa yol A → B → E → G → D → H = 16.

En Kısa Yol · Kodu adım adım çalıştır

Kod İzleme: onceki[] ile en kısa yolu yazdırma

4 2 5 10 3 4 11 A B D C E F v onceki – A A B A C E D C E D F y addFirst → hedeften kaynağa doğru, başa ekle

Dijkstra'nın bıraktığı onceki[]: her düğüm için en kısa yolda kendinden önceki düğüm. Boş liste y.

4 2 5 10 3 4 11 A B D C E F v onceki – A A B A C E D C E D F y addFirst → hedeften kaynağa doğru, başa ekle

Hedeften başla: v = F.

4 2 5 10 3 4 11 A B D C E F v onceki – A A B A C E D C E D F y F addFirst → hedeften kaynağa doğru, başa ekle

F listenin başına eklenir (sonra gelenler daha önceki düğümler).

4 2 5 10 3 4 11 A B D C E F v onceki – A A B A C E D C E D F y F addFirst → hedeften kaynağa doğru, başa ekle

v = onceki[…] = D: bir adım geri.

4 2 5 10 3 4 11 A B D C E F v onceki – A A B A C E D C E D F y D F addFirst → hedeften kaynağa doğru, başa ekle

D listenin başına eklenir (sonra gelenler daha önceki düğümler).

4 2 5 10 3 4 11 A B D C E F v onceki – A A B A C E D C E D F y D F addFirst → hedeften kaynağa doğru, başa ekle

v = onceki[…] = E: bir adım geri.

4 2 5 10 3 4 11 A B D C E F v onceki – A A B A C E D C E D F y E D F addFirst → hedeften kaynağa doğru, başa ekle

E listenin başına eklenir (sonra gelenler daha önceki düğümler).

4 2 5 10 3 4 11 A B D C E F v onceki – A A B A C E D C E D F y E D F addFirst → hedeften kaynağa doğru, başa ekle

v = onceki[…] = C: bir adım geri.

4 2 5 10 3 4 11 A B D C E F v onceki – A A B A C E D C E D F y C E D F addFirst → hedeften kaynağa doğru, başa ekle

C listenin başına eklenir (sonra gelenler daha önceki düğümler).

4 2 5 10 3 4 11 A B D C E F v onceki – A A B A C E D C E D F y C E D F addFirst → hedeften kaynağa doğru, başa ekle

v = onceki[…] = A: bir adım geri.

4 2 5 10 3 4 11 A B D C E F v onceki – A A B A C E D C E D F y A C E D F addFirst → hedeften kaynağa doğru, başa ekle

A listenin başına eklenir (sonra gelenler daha önceki düğümler).

4 2 5 10 3 4 11 A B D C E F v onceki – A A B A C E D C E D F y A C E D F addFirst → hedeften kaynağa doğru, başa ekle

onceki[A] = −1: kaynağa varıldı, döngü biter. 5 tur = yoldaki düğüm sayısı → O(yol uzunluğu).

4 2 5 10 3 4 11 A B D C E F v onceki – A A B A C E D C E D F y A C E D F addFirst → hedeften kaynağa doğru, başa ekle

İlk öğe kaynak A mı? Evet → t ulaşılabilir. (Ulaşılamayan t için zincir A'ya varmaz; boş liste döner.)

4 2 5 10 3 4 11 A B D C E F v onceki – A A B A C E D C E D F y A C E D F addFirst → hedeften kaynağa doğru, başa ekle

Sonuç A → C → E → D → F, uzunluk d[F] = 2 + 3 + 4 + 11 = 20.

List<Integer> yol(int[] onceki, int s, int t) {
  LinkedList<Integer> y = new LinkedList<>();
  for (int v = t; v != -1; v = onceki[v])
    y.addFirst(v);
  if (y.getFirst() != s) return List.of();
  return y;                 // s ... t
}

En Kısa Yol

Dijkstra Algoritmasının Analizi

UygulamaKarmaşıklıkNeden?
Öncelikli kuyruk (ikili heap)O((n + m) log n)n kez en küçüğü çıkar, en çok m kez güncelle/ekle; her biri O(log n)
Kuyruksuz (dizi taraması)O(n² + m) = O(n²)Her adımda en küçük mesafeli düğümü bulmak için n düğüm taranır; komşu kontrolleri toplam m
Hangisi ne zaman?Seyrek çizgede (m ≈ n) heap: O(n log n). Çok yoğun çizgede (m ≈ n²) dizi taraması O(n²) daha iyi olabilir.
Negatif ağırlıkKesinleşen bir mesafe sonradan negatif kenarla kısalabilir → sözde koddaki Dijkstra yanlış sonuç verir. Bayat kayıtlı Java sürümü düğümü yeniden işleyip doğruyu bulabilir ama süre garantisi kaybolur, negatif döngüde bitmez. Bu durumda Bellman-Ford kullanılır.
Neden doğru? Ağırlıklar ≥ 0 iken, kuyruktaki en küçük mesafeli düğüme başka bir düğüm üzerinden daha kısa ulaşılamaz: öbür yollar zaten en az bu kadar uzundur.

Minimum Kapsayan Ağaç

Minimum Kapsayan Ağaç (Minimum Spanning Tree)

  • Kapsayan ağaç (spanning tree): bağlantılı, ağırlıklı bir çizgenin tüm düğümlerini içeren ve döngü içermeyen alt çizgesi; n düğüm için n − 1 kenar.
  • Minimum kapsayan ağaç (MKA, MST): toplam kenar ağırlığı en düşük olan kapsayan ağaç.
  • Uygulama: şehirleri en az kabloyla / boruyla birbirine bağlamak.
  • Kruskal algoritması, "bu kenar döngü oluşturur mu?" sorusunu Union-Find (ayrık kümeler) ile yanıtlar: find(x) x'in kümesinin temsilcisini verir; union(u, v) farklı iki kümeyi birleştirip true, aynı kümedeyse false döndürür.
0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J

Minimum Kapsayan Ağaç

Kruskal Algoritması

Kruskal(G):
  T = ∅          // seçilen kenarlar
  for her düğüm v: makeSet(v)
  kenarları ağırlığa göre sırala
  for her (u, v), küçükten büyüğe:
    if find(u) != find(v): // döngü yok
      T.ekle((u, v))
      union(u, v)
    if |T| == n − 1: break
  return T  // MST (bağlı değilse: orman)
  • Açgözlü: her zaman döngü oluşturmayan en hafif kenarı seç.
  • u ve v zaten aynı kümedeyse, kenar bir döngü kapatır → atla.
  • Başta n ayrık küme; her kabul edilen kenar iki kümeyi birleştirir.
  • Çizge bağlantısızsa n−1 kenara ulaşılamaz; algoritma her bağlantılı bileşen için bir ağaçtan oluşan minimum kapsayan orman döndürür.
SıralamaO(m log m)
2m find + (n−1) unionO(m · α(n))
ToplamO(m log n)

Minimum Kapsayan Ağaç

Kruskal Algoritması Adım Adım

I–J = 0 A–E = 1 C–I = 1 E–F = 1 G–H = 1 B–D = 2 C–J = 2 D–E = 2 D–H = 2 A–D = 4 B–C = 4 C–H = 4 G–I = 4 A–B = 5 D–F = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Seçilen kenar 0 / 9 Toplam ağırlık 0

Kenarlar ağırlığa göre sıralandı (solda). Başlangıçta 10 düğüm = 10 ayrı küme, T boş.

I–J = 0 ✓ A–E = 1 C–I = 1 E–F = 1 G–H = 1 B–D = 2 C–J = 2 D–E = 2 D–H = 2 A–D = 4 B–C = 4 C–H = 4 G–I = 4 A–B = 5 D–F = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Seçilen kenar 1 / 9 Toplam ağırlık 0

I–J (0): find(I) ≠ find(J) → kabul, kümeler birleşir.

I–J = 0 ✓ A–E = 1 ✓ C–I = 1 E–F = 1 G–H = 1 B–D = 2 C–J = 2 D–E = 2 D–H = 2 A–D = 4 B–C = 4 C–H = 4 G–I = 4 A–B = 5 D–F = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Seçilen kenar 2 / 9 Toplam ağırlık 1

A–E (1): find(A) ≠ find(E) → kabul, kümeler birleşir.

I–J = 0 ✓ A–E = 1 ✓ C–I = 1 ✓ E–F = 1 G–H = 1 B–D = 2 C–J = 2 D–E = 2 D–H = 2 A–D = 4 B–C = 4 C–H = 4 G–I = 4 A–B = 5 D–F = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Seçilen kenar 3 / 9 Toplam ağırlık 2

C–I (1): find(C) ≠ find(I) → kabul, kümeler birleşir.

I–J = 0 ✓ A–E = 1 ✓ C–I = 1 ✓ E–F = 1 ✓ G–H = 1 B–D = 2 C–J = 2 D–E = 2 D–H = 2 A–D = 4 B–C = 4 C–H = 4 G–I = 4 A–B = 5 D–F = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Seçilen kenar 4 / 9 Toplam ağırlık 3

E–F (1): find(E) ≠ find(F) → kabul, kümeler birleşir.

I–J = 0 ✓ A–E = 1 ✓ C–I = 1 ✓ E–F = 1 ✓ G–H = 1 ✓ B–D = 2 C–J = 2 D–E = 2 D–H = 2 A–D = 4 B–C = 4 C–H = 4 G–I = 4 A–B = 5 D–F = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Seçilen kenar 5 / 9 Toplam ağırlık 4

G–H (1): find(G) ≠ find(H) → kabul, kümeler birleşir.

I–J = 0 ✓ A–E = 1 ✓ C–I = 1 ✓ E–F = 1 ✓ G–H = 1 ✓ B–D = 2 ✓ C–J = 2 D–E = 2 D–H = 2 A–D = 4 B–C = 4 C–H = 4 G–I = 4 A–B = 5 D–F = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Seçilen kenar 6 / 9 Toplam ağırlık 6

B–D (2): find(B) ≠ find(D) → kabul, kümeler birleşir.

I–J = 0 ✓ A–E = 1 ✓ C–I = 1 ✓ E–F = 1 ✓ G–H = 1 ✓ B–D = 2 ✓ C–J = 2 ✗ D–E = 2 D–H = 2 A–D = 4 B–C = 4 C–H = 4 G–I = 4 A–B = 5 D–F = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Seçilen kenar 6 / 9 Toplam ağırlık 6

C–J (2): C ve J zaten aynı kümede → döngü oluşturur, reddedilir.

I–J = 0 ✓ A–E = 1 ✓ C–I = 1 ✓ E–F = 1 ✓ G–H = 1 ✓ B–D = 2 ✓ C–J = 2 ✗ D–E = 2 ✓ D–H = 2 A–D = 4 B–C = 4 C–H = 4 G–I = 4 A–B = 5 D–F = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Seçilen kenar 7 / 9 Toplam ağırlık 8

D–E (2): find(D) ≠ find(E) → kabul, kümeler birleşir.

I–J = 0 ✓ A–E = 1 ✓ C–I = 1 ✓ E–F = 1 ✓ G–H = 1 ✓ B–D = 2 ✓ C–J = 2 ✗ D–E = 2 ✓ D–H = 2 ✓ A–D = 4 B–C = 4 C–H = 4 G–I = 4 A–B = 5 D–F = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Seçilen kenar 8 / 9 Toplam ağırlık 10

D–H (2): find(D) ≠ find(H) → kabul, kümeler birleşir.

I–J = 0 ✓ A–E = 1 ✓ C–I = 1 ✓ E–F = 1 ✓ G–H = 1 ✓ B–D = 2 ✓ C–J = 2 ✗ D–E = 2 ✓ D–H = 2 ✓ A–D = 4 ✗ B–C = 4 C–H = 4 G–I = 4 A–B = 5 D–F = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Seçilen kenar 8 / 9 Toplam ağırlık 10

A–D (4): A ve D zaten aynı kümede → döngü oluşturur, reddedilir.

I–J = 0 ✓ A–E = 1 ✓ C–I = 1 ✓ E–F = 1 ✓ G–H = 1 ✓ B–D = 2 ✓ C–J = 2 ✗ D–E = 2 ✓ D–H = 2 ✓ A–D = 4 ✗ B–C = 4 ✓ C–H = 4 G–I = 4 A–B = 5 D–F = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Seçilen kenar 9 / 9 Toplam ağırlık 14

B–C (4): find(B) ≠ find(C) → kabul, kümeler birleşir. 9 = n − 1 kenar seçildi: bitti, toplam ağırlık 14.

I–J = 0 ✓ A–E = 1 ✓ C–I = 1 ✓ E–F = 1 ✓ G–H = 1 ✓ B–D = 2 ✓ C–J = 2 ✗ D–E = 2 ✓ D–H = 2 ✓ A–D = 4 ✗ B–C = 4 ✓ C–H = 4 G–I = 4 A–B = 5 D–F = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Seçilen kenar 9 / 9 Toplam ağırlık 14

Minimum kapsayan ağaç: A–E, E–F, D–E, B–D, D–H, G–H, B–C, C–I, I–J. Kalan kenarlara bakmaya gerek yok.

Minimum Kapsayan Ağaç · Kodu adım adım çalıştır

Kod İzleme: kruskal() + Union-Find

List<int[]> kruskal(int n, List<int[]> E) {
  E.sort((a, b) ->          // {u, v, w}
      Integer.compare(a[2], b[2]));
  UnionFind uf = new UnionFind(n);
  List<int[]> T = new ArrayList<>();
  for (int[] e : E) {
    if (uf.union(e[0], e[1]))  // döngüsüz
      T.add(e);
    if (T.size() == n - 1) break;
  }
  return T;
}
A B C D E F G H I J kenar (sıralı) I–J 0 A–E 1 C–I 1 E–F 1 G–H 1 B–D 2 C–J 2 D–E 2 D–H 2 A–D 4 B–C 4 C–H 4 G–I 4 A–B 5 D–F 5 H–I 6 F–G 7 D–G 11 uf ormanı (ok → ebeveyn) A B C D E F G H I J |T|=0, ağırlık=0

Kenarlar ağırlığa göre sıralanır (A=0 … J=9; sort kararlıdır, eşit ağırlıklar girdi sırasında kalır). O(m log m).

A B C D E F G H I J kenar (sıralı) I–J 0 A–E 1 C–I 1 E–F 1 G–H 1 B–D 2 C–J 2 D–E 2 D–H 2 A–D 4 B–C 4 C–H 4 G–I 4 A–B 5 D–F 5 H–I 6 F–G 7 D–G 11 uf ormanı (ok → ebeveyn) A B C D E F G H I J |T|=0, ağırlık=0

new UnionFind(10): her düğüm kendi kümesi (10 kök). T boş.

A B C D E F G H I J kenar (sıralı) I–J 0 ✓ A–E 1 C–I 1 E–F 1 G–H 1 B–D 2 C–J 2 D–E 2 D–H 2 A–D 4 B–C 4 C–H 4 G–I 4 A–B 5 D–F 5 H–I 6 F–G 7 D–G 11 uf ormanı (ok → ebeveyn) A B C D E F G H I J |T|=1, ağırlık=0

I–J (0): kökler I ≠ J → union true: ağaçlar birleşir (I → J), kenar T'ye eklenir.

A B C D E F G H I J kenar (sıralı) I–J 0 ✓ A–E 1 ✓ C–I 1 E–F 1 G–H 1 B–D 2 C–J 2 D–E 2 D–H 2 A–D 4 B–C 4 C–H 4 G–I 4 A–B 5 D–F 5 H–I 6 F–G 7 D–G 11 uf ormanı (ok → ebeveyn) A B C D E F G H I J |T|=2, ağırlık=1

A–E (1): kökler A ≠ E → union true: ağaçlar birleşir (A → E), kenar T'ye eklenir.

A B C D E F G H I J kenar (sıralı) I–J 0 ✓ A–E 1 ✓ C–I 1 ✓ E–F 1 G–H 1 B–D 2 C–J 2 D–E 2 D–H 2 A–D 4 B–C 4 C–H 4 G–I 4 A–B 5 D–F 5 H–I 6 F–G 7 D–G 11 uf ormanı (ok → ebeveyn) A B C D E F G H I J |T|=3, ağırlık=2

C–I (1): kökler C ≠ J → union true: ağaçlar birleşir (C → J), kenar T'ye eklenir.

A B C D E F G H I J kenar (sıralı) I–J 0 ✓ A–E 1 ✓ C–I 1 ✓ E–F 1 ✓ G–H 1 B–D 2 C–J 2 D–E 2 D–H 2 A–D 4 B–C 4 C–H 4 G–I 4 A–B 5 D–F 5 H–I 6 F–G 7 D–G 11 uf ormanı (ok → ebeveyn) A B C D E F G H I J |T|=4, ağırlık=3

E–F (1): kökler E ≠ F → union true: ağaçlar birleşir (F → E), kenar T'ye eklenir.

A B C D E F G H I J kenar (sıralı) I–J 0 ✓ A–E 1 ✓ C–I 1 ✓ E–F 1 ✓ G–H 1 ✓ B–D 2 C–J 2 D–E 2 D–H 2 A–D 4 B–C 4 C–H 4 G–I 4 A–B 5 D–F 5 H–I 6 F–G 7 D–G 11 uf ormanı (ok → ebeveyn) A B C D E F G H I J |T|=5, ağırlık=4

G–H (1): kökler G ≠ H → union true: ağaçlar birleşir (G → H), kenar T'ye eklenir.

A B C D E F G H I J kenar (sıralı) I–J 0 ✓ A–E 1 ✓ C–I 1 ✓ E–F 1 ✓ G–H 1 ✓ B–D 2 ✓ C–J 2 D–E 2 D–H 2 A–D 4 B–C 4 C–H 4 G–I 4 A–B 5 D–F 5 H–I 6 F–G 7 D–G 11 uf ormanı (ok → ebeveyn) A B C D E F G H I J |T|=6, ağırlık=6

B–D (2): kökler B ≠ D → union true: ağaçlar birleşir (B → D), kenar T'ye eklenir.

A B C D E F G H I J kenar (sıralı) I–J 0 ✓ A–E 1 ✓ C–I 1 ✓ E–F 1 ✓ G–H 1 ✓ B–D 2 ✓ C–J 2 ✗ D–E 2 D–H 2 A–D 4 B–C 4 C–H 4 G–I 4 A–B 5 D–F 5 H–I 6 F–G 7 D–G 11 uf ormanı (ok → ebeveyn) A B C D E F G H I J |T|=6, ağırlık=6

C–J (2): find(C) = find(J) = J → aynı ağaç, union false döner: kenar döngü kurar, atlanır.

A B C D E F G H I J kenar (sıralı) I–J 0 ✓ A–E 1 ✓ C–I 1 ✓ E–F 1 ✓ G–H 1 ✓ B–D 2 ✓ C–J 2 ✗ D–E 2 ✓ D–H 2 A–D 4 B–C 4 C–H 4 G–I 4 A–B 5 D–F 5 H–I 6 F–G 7 D–G 11 uf ormanı (ok → ebeveyn) A B C D E F G H I J |T|=7, ağırlık=8

D–E (2): kökler D ≠ E → union true: ağaçlar birleşir (D → E), kenar T'ye eklenir.

A B C D E F G H I J kenar (sıralı) I–J 0 ✓ A–E 1 ✓ C–I 1 ✓ E–F 1 ✓ G–H 1 ✓ B–D 2 ✓ C–J 2 ✗ D–E 2 ✓ D–H 2 ✓ A–D 4 B–C 4 C–H 4 G–I 4 A–B 5 D–F 5 H–I 6 F–G 7 D–G 11 uf ormanı (ok → ebeveyn) A B C D E F G H I J |T|=8, ağırlık=10

D–H (2): kökler E ≠ H → union true: ağaçlar birleşir (H → E), kenar T'ye eklenir.

A B C D E F G H I J kenar (sıralı) I–J 0 ✓ A–E 1 ✓ C–I 1 ✓ E–F 1 ✓ G–H 1 ✓ B–D 2 ✓ C–J 2 ✗ D–E 2 ✓ D–H 2 ✓ A–D 4 ✗ B–C 4 C–H 4 G–I 4 A–B 5 D–F 5 H–I 6 F–G 7 D–G 11 uf ormanı (ok → ebeveyn) A B C D E F G H I J |T|=8, ağırlık=10

A–D (4): find(A) = find(D) = E → aynı ağaç, union false döner: kenar döngü kurar, atlanır.

A B C D E F G H I J kenar (sıralı) I–J 0 ✓ A–E 1 ✓ C–I 1 ✓ E–F 1 ✓ G–H 1 ✓ B–D 2 ✓ C–J 2 ✗ D–E 2 ✓ D–H 2 ✓ A–D 4 ✗ B–C 4 ✓ C–H 4 G–I 4 A–B 5 D–F 5 H–I 6 F–G 7 D–G 11 uf ormanı (ok → ebeveyn) A B C D E F G H I J |T|=9, ağırlık=14

B–C (4): kökler E ≠ J → union true: ağaçlar birleşir (J → E), kenar T'ye eklenir. |T| = 9 = n − 1 → break.

A B C D E F G H I J kenar (sıralı) I–J 0 ✓ A–E 1 ✓ C–I 1 ✓ E–F 1 ✓ G–H 1 ✓ B–D 2 ✓ C–J 2 ✗ D–E 2 ✓ D–H 2 ✓ A–D 4 ✗ B–C 4 ✓ C–H 4 G–I 4 A–B 5 D–F 5 H–I 6 F–G 7 D–G 11 uf ormanı (ok → ebeveyn) A B C D E F G H I J |T|=9, ağırlık=14

return T: 9 kenar, toplam ağırlık 14. Tek ağaç kaldı. Kalan 7 kenara hiç bakılmadı.

Minimum Kapsayan Ağaç

İkinci Örnek: Havalimanları

2704 867 849 740 621 1846 802 144 187 184 1258 337 1464 1235 1391 946 1090 1121 2342 BOS PVD ORD JFK BWI SFO LAX DFW MIA

Goodrich'teki örnek: 9 havalimanı, 19 uçuş hattı (mil). Kruskal sırası:

144, 184, 187, 337, 621kabul
740 ORD–JFKret (döngü)
802kabul
849, 867ret
946kabul
1090, 1121ret
1235 LAX–DFWkabul → 8 kenar

Toplam: 4456 mil.

Minimum Kapsayan Ağaç

Prim Algoritması

Prim(G, s):
  ağaç = {s}, T = ∅
  s'nin kenarlarını kuyruğa ekle
  while |T| < n − 1:
    (u, v) = en hafif kenar  // u ağaçta
    if v ağaçta: atla        // döngü
    v'yi ağaca, (u, v)'yi T'ye ekle
    v'nin dışarı giden kenarlarını
      kuyruğa ekle
  return T
  • Ağaç tek bir düğümden başlar ve her adımda bir düğüm büyür.
  • Her adımda, ağaçtaki bir düğümü ağaç dışındaki bir düğüme bağlayan kenarların en hafifi seçilir.
  • Ağacı dışarıya bağlayan kenarlardan en hafifi her zaman bir minimum kapsayan ağaçta bulunur: ağaç dışarıya bir yolla bağlanmak zorundadır ve bu kenar en ucuz bağlantıdır.
  • Dijkstra'ya benzer; fark kuyruğun anahtarıdır: kaynağa uzaklık değil, tek kenarın ağırlığı.
  • Kruskal'dan farkı: ara durumda hep tek bir ağaç vardır, Union-Find gerekmez.

Minimum Kapsayan Ağaç

Prim: Java (öncelikli kuyrukla, tembel sürüm)

List<int[]> prim(List<List<int[]>> adj, int s) {
  int n = adj.size();                 // adj.get(u): {v, w}
  boolean[] agacta = new boolean[n];
  PriorityQueue<int[]> pq = new PriorityQueue<>(
      (a, b) -> Integer.compare(a[2], b[2]));  // {u, v, w}
  List<int[]> T = new ArrayList<>();
  agacta[s] = true;
  for (int[] e : adj.get(s)) pq.add(new int[]{s, e[0], e[1]});
  while (!pq.isEmpty() && T.size() < n - 1) {
    int[] e = pq.poll();               // en hafif aday
    if (agacta[e[1]]) continue;       // bayat: döngü kurar
    agacta[e[1]] = true;
    T.add(e);
    for (int[] f : adj.get(e[1]))
      if (!agacta[f[0]]) pq.add(new int[]{e[1], f[0], f[1]});
  }
  return T;
}
  • Kuyrukta {u, v, w} kayıtları: u ağaçta, v aday.
  • Tembel sürüm: v ağaca girince v'ye giden eski kayıtlar silinmez; kuyruktan çıktıklarında continue ile atlanır (bayat kayıt).
  • Her kenar en çok iki kez kuyruğa girer: en çok 2m ekleme ve çıkarma, her biri O(log m).
  • Toplam O(m log m) = O(m log n); ek bellek O(m).

Minimum Kapsayan Ağaç

Prim Algoritması Adım Adım (A'dan)

öncelikli kuyruk A–E = 1 A–D = 4 A–B = 5 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Ağaçtaki düğüm 1 / 10 Toplam ağırlık 0

Başlangıç: ağaçta yalnız A. A'nın kenarları kuyruğa girer: A–E 1, A–D 4, A–B 5. Eşit ağırlıklarda alfabetik sıra izlenir.

öncelikli kuyruk E–F = 1 E–D = 2 A–D = 4 A–B = 5 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Ağaçtaki düğüm 2 / 10 Toplam ağırlık 1

A–E (1): ağaçla dışarıyı bağlayan en hafif kenar → E ağaca girer. Yeni adaylar: E–F, E–D.

öncelikli kuyruk E–D = 2 A–D = 4 A–B = 5 F–D = 5 F–G = 7 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Ağaçtaki düğüm 3 / 10 Toplam ağırlık 2

E–F (1): ağaçla dışarıyı bağlayan en hafif kenar → F ağaca girer. Yeni adaylar: F–D, F–G.

öncelikli kuyruk D–B = 2 D–H = 2 A–D = 4 A–B = 5 F–D = 5 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Ağaçtaki düğüm 4 / 10 Toplam ağırlık 4

E–D (2): ağaçla dışarıyı bağlayan en hafif kenar → D ağaca girer. Yeni adaylar: D–B, D–H, D–G. Üstü çizili kayıtlar bayatladı (iki ucu da ağaçta); kuyruktan çıkınca atlanır.

öncelikli kuyruk D–H = 2 B–C = 4 A–D = 4 A–B = 5 F–D = 5 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Ağaçtaki düğüm 5 / 10 Toplam ağırlık 6

D–B (2): ağaçla dışarıyı bağlayan en hafif kenar → B ağaca girer. Yeni adaylar: B–C.

öncelikli kuyruk H–G = 1 B–C = 4 H–C = 4 A–D = 4 A–B = 5 F–D = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Ağaçtaki düğüm 6 / 10 Toplam ağırlık 8

D–H (2): ağaçla dışarıyı bağlayan en hafif kenar → H ağaca girer. Yeni adaylar: H–G, H–C, H–I.

öncelikli kuyruk B–C = 4 H–C = 4 A–D = 4 G–I = 4 A–B = 5 F–D = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Ağaçtaki düğüm 7 / 10 Toplam ağırlık 9

H–G (1): ağaçla dışarıyı bağlayan en hafif kenar → G ağaca girer. Yeni adaylar: G–I. Üstü çizili kayıtlar bayatladı (iki ucu da ağaçta); kuyruktan çıkınca atlanır.

öncelikli kuyruk C–I = 1 C–J = 2 H–C = 4 A–D = 4 G–I = 4 A–B = 5 F–D = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Ağaçtaki düğüm 8 / 10 Toplam ağırlık 13

B–C (4): ağaçla dışarıyı bağlayan en hafif kenar → C ağaca girer. Yeni adaylar: C–I, C–J.

öncelikli kuyruk I–J = 0 C–J = 2 H–C = 4 A–D = 4 G–I = 4 A–B = 5 F–D = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Ağaçtaki düğüm 9 / 10 Toplam ağırlık 14

C–I (1): ağaçla dışarıyı bağlayan en hafif kenar → I ağaca girer. Yeni adaylar: I–J.

öncelikli kuyruk C–J = 2 H–C = 4 A–D = 4 G–I = 4 A–B = 5 F–D = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Ağaçtaki düğüm 10 / 10 Toplam ağırlık 14

I–J (0): ağaçla dışarıyı bağlayan en hafif kenar → J ağaca girer. 9 = n − 1 kenar: bitti, toplam ağırlık 14.

öncelikli kuyruk C–J = 2 H–C = 4 A–D = 4 G–I = 4 A–B = 5 F–D = 5 H–I = 6 F–G = 7 D–G = 11 0 1 1 1 1 2 2 2 2 4 4 4 4 5 5 6 7 11 A B C D E F G H I J Ağaçtaki düğüm 10 / 10 Toplam ağırlık 14

Prim ağacı: A–E, E–F, E–D, D–B, D–H, H–G, B–C, C–I, I–J. Kruskal ile aynı toplam ağırlık (14). Eşit ağırlıklar başka sırayla çıkarsa (ör. B–C yerine H–C) farklı ama yine 14 ağırlıklı bir ağaç bulunabilir.

Minimum Kapsayan Ağaç

Kruskal ve Prim Karşılaştırması

KruskalPrim
Fikirkenarları küçükten büyüğe dener, ağaçları birleştirirtek ağacı bir düğümden başlayıp büyütür
Ara durumorman (birden çok ağaç)tek ağaç
Veri yapısısıralı kenar listesi + Union-Findöncelikli kuyruk + işaret dizisi, komşuluk listesi
Döngü kontrolüfind(u) == find(v)v zaten ağaçta mı?
MaliyetO(m log n) (sıralama baskın)O(m log n) (heap ile); matrisle O(n²)
Ne zaman?seyrek çizge, kenarlar liste olarak hazırkomşuluk listesi hazır; çok yoğun çizgede O(n²) sürüm
İkisi de açgözlüdür ve aynı çizgede aynı toplam ağırlığı bulur (örnekte 14). Eşit ağırlıklı kenarlar varsa buldukları ağaçlar farklı olabilir.

Özet

Özet

KavramlarDüğüm, kenar, derece, yön, ağırlık, yol, döngü ve bağlantılı bileşen.
GösterimlerSeyrek çizgede komşuluk listesi; hızlı kenar sorgusunda matris.
AlgoritmaYapıZaman (liste ile)Ne verir?
BFSkuyrukO(n + m)seviye sırası, ağırlıksız en kısa yol
DFSyığın / özyinelemeO(n + m)derinlik öncelikli gezinme, döngü, bileşenler
Topolojikkuyruk / DFSO(n + m)DAG için bağımlılık sırası
Dijkstraöncelikli kuyrukO((n + m) log n)ağırlıklı en kısa yol (ağırlık ≥ 0)
Kruskalsıralama + Union-FindO(m log n)minimum kapsayan ağaç
Primöncelikli kuyrukO(m log n)minimum kapsayan ağaç
Veri yapısı algoritmanın davranışını belirler: BFS kuyruk, DFS yığın, Dijkstra ve Prim öncelikli kuyruk kullanır; topolojik sıralama ise yalnızca DAG'lerde tanımlıdır.

Özet

Etkileşimli Simülatörler

Yönsüz ÇizgeDüğüm/kenar ekle-sil, BFS ve DFS, bağlantılı bileşenler, komşuluk listesi ve matrisi görünümü.
Yönlü ÇizgeOklu kenarlar, giriş/çıkış dereceleri ve yönlü gezinme.
DijkstraAğırlıklı çizgede en kısa yolların adım adım bulunması.
Uygulama: Ders Ön Koşul Planlayıcı → Kahn algoritmasıyla derslerin dönem dönem planlanması ve ön koşul döngüsünün yakalanması.

Özet

Örnek Problemler

  1. 10 düğümlü basit yönsüz bir çizgede en fazla kaç kenar olabilir? Derecelerin toplamı 30 ise kaç kenar vardır?
  2. n = 10.000 düğüm, m = 30.000 kenar olan bir yol ağını hangi gösterimle saklarsınız? Neden?
  3. Gezinme örneğindeki çizgede BFS ve DFS'yi H'den başlatın (komşular alfabetik).
  4. DFS'yi yığın yerine kuyrukla yazarsak hangi algoritmayı elde ederiz?
  5. Ağırlıklı en kısa yol örneğinde B → C kenarı 5 yerine 1 olsaydı A'dan D'ye en kısa yol ne olurdu?
  6. Kruskal örneğinde C–J kenarı neden reddedildi?
  7. Prim'i aynı çizgede A yerine J'den başlatınca ilk üç seçilen kenar ve toplam ağırlık ne olur?
Cevapları göster
  1. 10·9/2 = 45 kenar; Σ deg = 2m → m = 15.
  2. Komşuluk listesi: O(n + m) ≈ 40 bin kayıt; matris 10⁸ hücre ister ve çoğu 0 olur.
  3. BFS: H D C G B E F A I · DFS: H D C B A F G E I.
  4. Ziyaret sırası BFS'ye dönüşür (yığının üstü yerine kuyruğun önü işlenir).
  5. A → C yolu değişmez (2 < 4 + 1); D için A → C → E → D = 2 + 3 + 4 = 9, yine 9.
  6. C–I ve I–J daha önce seçilmişti; C ile J aynı kümede, kenar C–I–J–C döngüsünü kapatır.
  7. J–I (0), I–C (1); kuyruktan çıkan C–J (2) bayattır, atlanır; üçüncü kenar C–B (4). Başlangıç düğümü toplamı değiştirmez: yine 14.

Özet

Alıştırmalar

  1. Yönsüz kenarlar (0,1), (0,2), (1,3), (2,3), (3,4), (4,5): 0'dan BFS sırası ve mesafeler? (komşular küçükten büyüğe)
  2. Aynı çizgenin komşuluk matrisinde kaç hücre 1'dir? Komşuluk listesinde toplam kaç kayıt vardır?
  3. Yönlü 0→1, 1→2, 2→0, 2→3 için donguVar(0) hangi kenarı incelerken true döner?
  4. 0→1, 0→2, 1→3, 2→3 DAG'ı için kaç farklı topolojik sıra vardır? Yazın.
  5. onceki = [-1, 0, 0, 1, 3] ise 0'dan 4'e yol nedir? 2'den 4'e?
  6. 5 düğümlü bir döngü (C5) iki parçalı mıdır? Bağlantılı bileşen sayısı kaçtır?
  7. Tembel Prim'de kuyruğa en çok kaç kayıt girer? Kayıt ne zaman bayatlar?
Cevaplar / ipuçları
  1. Sıra 0 1 2 3 4 5; mesafeler 0, 1, 1, 2, 3, 4.
  2. 2m = 12 hücre (simetrik); listede de 2m = 12 kayıt.
  3. 2 → 0 kenarında: 0 gri (yolda) → geri kenar.
  4. İki: 0 1 2 3 ve 0 2 1 3.
  5. 0 → 1 → 3 → 4. onceki zinciri 2'ye uğramaz: 2'den değil, 0 kaynağından kurulmuş yol ağacıdır.
  6. Hayır (tek uzunlukta döngü). Bağlantılı: 1 bileşen.
  7. Her kenar en çok iki kez (iki ucundan): 2m. Hedef düğümü ağaca girince bayatlar.

Özet

Kaynaklar

  • Goodrich, Tamassia ve Goldwasser, Data Structures and Algorithms in Java, 6. baskı, 2014.
  • Cormen, Leiserson, Rivest ve Stein, Introduction to Algorithms, 4. baskı, 2022.
  • Sedgewick ve Wayne, Algorithms, 4. baskı, 2011.

Son

Bölüm 14: Çizgeler
Çalışma soruları · Simülatörler: Undirected Graph Simulator, Directed Graph Simulator, Dijkstra Algorithm Simulator, Course Prerequisite Planner · Terim sözlüğü
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.