Bölüm 4.3: Minimum Kapsayan Ağaç Algoritmaları

Algoritmalar
Kapsayan ağaçKesim ve döngü özelliğiKruskalUnion-Find PrimBorůvkaTers silmeKarşılaştırma
Sercan KÜLCÜ · Giresun Üniversitesi · Bilgisayar Mühendisliği

Giriş

Öğrenme Çıktıları

Kavram

Kapsayan ağacı ve minimum kapsayan ağacı (MST) tanımlamak; V − 1 kenar, kesim ve döngü özelliklerini açıklamak.

Kruskal ve Union-Find

Kenarları sıralayıp döngü oluşturmayanları seçmek; döngü denetimini ayrık kümelerle (bul / birleştir) yapmak.

Prim

Ağacı bir düğümden büyütmek; anahtar ve ebeveyn dizilerini öncelikli kuyrukla adım adım izlemek.

Borůvka, Ters Silme, Analiz

Bileşen tabanlı ve silme tabanlı yaklaşımları uygulamak; dört algoritmanın karmaşıklığını karşılaştırıp uygun olanı seçmek.

MST Kavramı

Kapsayan Ağaç ve Minimum Kapsayan Ağaç

  • G = (V, E): bağlı, yönsüz ve kenarları ağırlıklı bir çizge.
  • Kapsayan ağaç (spanning tree): tüm düğümleri içeren, bağlı ve döngüsüz alt çizge. Her zaman tam V − 1 kenarı vardır.
  • Minimum kapsayan ağaç (Minimum Spanning Tree, MST): kenar ağırlıkları toplamı en küçük olan kapsayan ağaç.
  • Ağaca bir kenar eklemek döngü oluşturur; bir kenar silmek ağacı ikiye böler.
3154276aebcd
Bir çizgenin çok sayıda kapsayan ağacı olabilir (n düğümlü tam çizgede nn−2 tane, Cayley formülü). Hepsini denemek yerine açgözlü (greedy) algoritmalar MST'yi doğrudan bulur. Yandaki çizgede MST ağırlığı w(T) = 1 + 2 + 3 + 5 = 11.

MST Kavramı

Örnek: "MST" Çizgesi

152251610781011254118202524124050
  • 15 düğüm, 20 kenar. Kalın 14 kenar (= V − 1) minimum kapsayan ağacı oluşturur: toplam ağırlık 141.
  • İnce kenarlar dışarıda kalır: her biri, kalın kenarlarla bir döngü kapatır ve o döngünün en ağır kenarıdır (ör. 15, 16, 18, 25, 40, 50).
  • Ağırlığı yüksek (20, 24, 25) kenarlar da seçilebilir: hiçbir döngünün en ağırı değildirler. Örneğin 40'ın kapattığı döngüde üçü de vardır; o döngünün en ağırı 40'tır.

MST Kavramı

Kesim Özelliği ve Döngü Özelliği

Kesim özelliği (cut property)Düğümleri iki kümeye ayıran her kesimde, kesimi geçen en hafif kenar bir MST'ye aittir.
kesim3154276aebcd

{a, b} | {c, d, e}: geçen kenarlar ae = 1, be = 4, bc = 5 → ae güvenli.

Döngü özelliği (cycle property)Herhangi bir döngünün en ağır kenarı (tekse) hiçbir MST'de yer almaz.
3154276aebcd

b–c–e döngüsü: 4, 5, 6 → ec = 6 asla seçilmez.

Kruskal ve Prim kesim özelliğini, ters silme döngü özelliğini kullanır. Tüm ağırlıklar farklıysa MST tektir.

MST Kavramı

Açgözlü MST Algoritmaları

Dört algoritmanın hepsi açgözlüdür: her adımda yerel olarak en iyi kenarı seçer (ya da en kötüsünü atar) ve bu seçim hiçbir zaman geri alınmaz.

AlgoritmaFikirYardımcı yapıZaman
Kruskal (1956)Kenarları küçükten büyüğe sırala, döngü oluşturmayanları ekleunion-findO(E log E)
Prim (1957)Bir düğümden başla, ağacı en ucuz komşu kenarla büyütöncelikli kuyrukO((V + E) log V)
Borůvka (1926)Her bileşen kendi en ucuz kenarını aynı anda eklerunion-findO(E log V)
Ters silmeKenarları büyükten küçüğe dene, bağlılığı bozmayanı silBFS/DFS ya da union-findO(E · (V + E))
Hepsi aynı ağırlıkta bir MST bulur; ağırlıklar farklıysa aynı ağacı bulurlar. Fark, kenarları hangi sırayla ele aldıkları ve gereken veri yapısındadır.

MST Kavramı

Nerede Kullanılır?

Ağ tasarımıŞehirleri en az kabloyla bağlamak: elektrik, su, fiber, yol ağları. Borůvka'nın çıkış noktası Moravya'nın elektrik ağıdır.
KümelemeMST'den en ağır k − 1 kenar silinirse k küme kalır (tek bağlantılı kümeleme, single-linkage).
Yaklaşık algoritmalarMetrik gezgin satıcı probleminde (TSP) MST tabanlı tur, en iyinin en fazla 2 katıdır.
Görüntü işlemePikselleri düğüm, renk farkını ağırlık sayarak bölütleme (segmentation).
Devre tasarımıBacakları en kısa toplam iletkenle bağlamak (VLSI yönlendirme ön adımı).
Diğer çizge problemleriDarboğaz yol (en büyük kenarı en küçük yol) MST üzerindedir; Steiner ağacı için temel yaklaşım.

Kruskal

Kruskal Algoritması

  • Çizgedeki tüm düğümleri birbirine bağlayan, toplam ağırlığı en küçük ağacı oluşturur; açgözlü (greedy) bir yaklaşımdır.
  • Joseph Kruskal tarafından geliştirilmiştir (1956).
  • Başlangıçta her düğüm ayrı bir ağaçtır (orman); adım adım bu ağaçlar birleştirilir.
  • Kenarlar küçükten büyüğe sıralanır; döngü oluşturmayan kenar seçilir, döngü oluşturan atlanır.
1223457abcdefyeşil: seçilen · kırmızı: döngü (atla)mavi: sıradaki, iki ağacı birleştirir

Güçlü yönler

  • Seyrek çizgelerde (E ≈ V) çok uygun.
  • Basit: kenar listesi + union-find yeterli.
  • Bağlı olmayan çizgede minimum kapsayan orman verir.

Zayıf yönler

  • Kenar sıralama maliyeti: O(E log E).
  • Yoğun çizgede (E ≈ V²) Prim daha hızlı olabilir.
  • Döngü denetimi için ek yapı (union-find) gerekir.

Kruskal

Kruskal: Adımlar ve Sözde Kod

  1. Çizgedeki tüm kenarlar ağırlıklarına göre sıralanır.
  2. Sıralı kenarlar arasından sıradaki en küçük ağırlıklı kenar seçilir.
  3. Kenar farklı ağaçlara ait iki düğümü birleştiriyorsa (döngü oluşturmuyorsa) ağaca eklenir ve iki ağaç birleştirilir.
  4. Aynı ağacın iki düğümünü bağlıyorsa döngü oluşturur: atlanır.
  5. V − 1 kenar seçilene (ya da kenarlar bitene) kadar 2–4 tekrarlanır.
KRUSKAL(G):
  MST = [ ]
  ayrikKume.oluştur(V)
  kenarlar.sırala(artana göre)
  her bir (u, v, ağırlık) için kenarlar içinde:
    eğer ayrikKume.bul(u) ≠ ayrikKume.bul(v):
      MST.ekle((u, v, ağırlık))
      ayrikKume.birleştir(u, v)
  döndür MST

"Aynı ağaçta mı?" sorusu union-find (ayrık kümeler) yapısıyla neredeyse sabit zamanda yanıtlanır.

Kruskal

Kruskal Adım Adım

ab3ae1bc5be4cd2ed7ec63154276aebcd
MST—
w(T)0
Ağaçlar{a} {b} {c} {d} {e}

Başlangıç: her düğüm ayrı bir ağaçtır (5 ağaçlı orman). Kenar tablosu henüz sırasız.

ae1cd2ab3be4bc5ec6ed73154276aebcd
MST—
w(T)0
Ağaçlar{a} {b} {c} {d} {e}

Adım 1: kenarlar artan ağırlığa göre sıralanır: ae, cd, ab, be, bc, ec, ed.

ae1cd2ab3be4bc5ec6ed73154276aebcd
MSTae
w(T)1
Ağaçlar{a, e} {b} {c} {d}

ae = 1: a ve e farklı ağaçlarda → kenar eklenir, iki ağaç birleşir.

ae1cd2ab3be4bc5ec6ed73154276aebcd
MSTae, cd
w(T)3
Ağaçlar{a, e} {c, d} {b}

cd = 2: c ve d farklı ağaçlarda → kenar eklenir, iki ağaç birleşir.

ae1cd2ab3be4bc5ec6ed73154276aebcd
MSTae, cd, ab
w(T)6
Ağaçlar{a, b, e} {c, d}

ab = 3: a ve b farklı ağaçlarda → kenar eklenir, iki ağaç birleşir.

ae1cd2ab3be4bc5ec6ed73154276aebcd
MSTae, cd, ab
w(T)6
Ağaçlar{a, b, e} {c, d}

be = 4: b ve e zaten aynı ağaçta → eklenirse döngü oluşur, atlanır.

ae1cd2ab3be4bc5ec6ed73154276aebcd
MSTae, cd, ab, bc
w(T)11
Ağaçlar{a, b, c, d, e}

bc = 5: b ve c farklı ağaçlarda → kenar eklenir, iki ağaç birleşir.

ae1cd2ab3be4bc5ec6ed73154276aebcd
MSTae, cd, ab, bc
w(T)11
Ağaçlartek ağaç

V − 1 = 4 kenar seçildi: ağaç kuruldu, w(T) = 11. ec ve ed'ye bakmaya gerek yoktur.

Kruskal

Union-Find (Ayrık Kümeler, Disjoint Set)

  • Kesişmeyen kümeleri tutar. Her küme bir ağaçtır; kökü kümenin temsilcisidir. Ebeveyn dizisi ata[]: ata[i] i'nin ebeveyni, kökte ata[r] = r.
  • oluştur(V): her düğüm kendi kümesi → ata[i] = i.
  • bul(x) (find): köke kadar çık, kökü döndür.
  • birleştir(x, y) (union): bir kökü diğerinin altına bağla.
  • Kruskal'da: bul(u) == bul(v) ise u ve v aynı ağaçtadır → kenar döngü kapatır.
int bul(int[] ata, int i) {
  if (ata[i] != i)
    ata[i] = bul(ata, ata[i]); // yol sıkıştırma
  return ata[i];
}
void birlestir(int[] ata, int x, int y) {
  ata[bul(ata, x)] = bul(ata, y);
}
İki iyileştirme: yol kısaltma (path compression) ve rütbeye göre birleştirme (union by rank). İkisi birlikte işlem başına amortize O(α(V)) verir; α (ters Ackermann) pratikte ≤ 4'tür.

Kruskal

Union-Find ile Döngü Denetimi

1234567acbdeAyrık küme ormanı (ok: ebeveyn)abcdeata[ ]aabbccddee

oluştur(5): her düğüm kendi kümesinin kökü, ata[i] = i. Kenarlar: ac 1, de 2, ab 3, bc 4, bd 5, cd 6, ce 7.

1234567acbdeAyrık küme ormanı (ok: ebeveyn)abcdeata[ ]cabbccddee

ac = 1: bul(a) = a, bul(c) = c → farklı → kenar MST'ye; ata[a] = c.

1234567acbdeAyrık küme ormanı (ok: ebeveyn)abcdeata[ ]cabbccedee

de = 2: bul(d) = d, bul(e) = e → farklı → kenar MST'ye; ata[d] = e.

1234567acbdeAyrık küme ormanı (ok: ebeveyn)abcdeata[ ]cabbbcedee

ab = 3: bul(a) = c, bul(b) = b → farklı → kenar MST'ye; ata[c] = b.

1234567acbdeAyrık küme ormanı (ok: ebeveyn)abcdeata[ ]cabbbcedee

bc = 4: bul(b) = b (yol b), bul(c) = b → aynı kök: döngü, kenar atlanır.

1234567acbdeAyrık küme ormanı (ok: ebeveyn)abcdeata[ ]caebbcedee

bd = 5: bul(b) = b, bul(d) = e → farklı → kenar MST'ye; ata[b] = e.

1234567acbdeAyrık küme ormanı (ok: ebeveyn)abcdeata[ ]caebbcedee

MST tamam (4 kenar, w = 11). Ama orman uzun bir zincir oldu: bul(a) a→c→b→e yolunu izler (3 adım).

1234567acbdeAyrık küme ormanı (ok: ebeveyn)abcdeata[ ]eaebecedee

Yol kısaltma: bul(a) dönerken yoldaki her düğümü doğrudan köke bağlar (ata[a] = ata[c] = e). Sonraki aramalar 1 adım.

Kruskal · Kodu adım adım çalıştır

Union-Find: bul ve birlestir İzleme

ayrık küme ormanı (ok: ebeveyn)01234ata[ ]1011223344

Başta her öğe kendi kümesinin kökü: ata[i] = i. birlestir(0, 1): bul(0) = 0, bul(1) = 1 → ata[0] = 1; 0 artık 1'in altında.

ayrık küme ormanı (ok: ebeveyn)01234ata[ ]1021223344

birlestir(1, 2): bul(1) = 1, bul(2) = 2 → ata[1] = 2. Kök kökün altına bağlandı; zincir uzadı: 0 → 1 → 2.

ayrık küme ormanı (ok: ebeveyn)01234ata[ ]1021323344

birlestir(2, 3): ata[2] = 3. Zincir 0 → 1 → 2 → 3: bul(0) artık 3 adım sürer.

ayrık küme ormanı (ok: ebeveyn)01234ata[ ]1021323344

ata[0] = 1 ≠ 0: 0 kök değil → bul(1) çağrılır.

ayrık küme ormanı (ok: ebeveyn)01234ata[ ]1021323344

ata[1] = 2 ≠ 1: 1 kök değil → bul(2) çağrılır.

ayrık küme ormanı (ok: ebeveyn)01234ata[ ]1021323344

ata[2] = 3 ≠ 2: 2 kök değil → bul(3) çağrılır.

ayrık küme ormanı (ok: ebeveyn)01234ata[ ]1021323344

ata[3] = 3: 3 kök. Kök 3 döndürülür; özyineleme geri sarılmaya başlar.

ayrık küme ormanı (ok: ebeveyn)01234ata[ ]1021323344

Dönüşte ata[2] = 3 (zaten köke bağlıydı, değişmedi).

ayrık küme ormanı (ok: ebeveyn)01234ata[ ]1031323344

Dönüşte ata[1] = 3: 1 artık doğrudan köke bağlı (2 → 3). Yol sıkıştırma.

ayrık küme ormanı (ok: ebeveyn)01234ata[ ]3031323344

Dönüşte ata[0] = 3: 0 artık doğrudan köke bağlı (1 → 3). Yol sıkıştırma.

ayrık küme ormanı (ok: ebeveyn)01234ata[ ]3031323344

bul(0) = 3. Yoldaki 0, 1, 2 düğümlerinin hepsi artık doğrudan 3'e bağlı: sonraki bul çağrıları tek adımda biter.

ayrık küme ormanı (ok: ebeveyn)01234ata[ ]3031323334

birlestir(4, 0): bul(4) = 4, bul(0) = 3 (tek adım!) → ata[4] = 3. Tüm öğeler tek kümede, kök 3.

int bul(int[] ata, int i) {
  if (ata[i] != i)
    ata[i] = bul(ata, ata[i]); // yol sıkıştırma
  return ata[i];
}
void birlestir(int[] ata, int x, int y) {
  ata[bul(ata, x)] = bul(ata, y);
}

Kruskal · Kodu adım adım çalıştır

Kruskal: Kodu Adım Adım İzle

22344612534

Kenarlar sıralanır: (1,3)=2, (2,5)=2, (1,2)=3, (2,3)=4, (3,4)=4, (1,4)=6.

22344612534

ata[i] = i: her düğüm ayrı bir ağaç (5 ağaç).

22344612534

e = (1,3), ağırlık 2: bul(1) = 1, bul(3) = 3.

22344612534

x ≠ y → (1,3) MST'ye eklenir, ata[1] = 3. v1 ve v3 birleşir.

22344612534

e = (2,5), ağırlık 2: bul(2) = 2, bul(5) = 5.

22344612534

x ≠ y → (2,5) MST'ye eklenir, ata[2] = 5. v2 ve v5 birleşir.

22344612534

e = (1,2), ağırlık 3: bul(1) = 3, bul(2) = 5.

22344612534

x ≠ y → (1,2) MST'ye eklenir, ata[3] = 5. Önceki iki ağaç birleşir.

22344612534

e = (2,3), ağırlık 4: bul(2) = 5, bul(3) = 5.

22344612534

x = y = 5: (2,3) iki ayrı ağacı birleştirmiyor → döngü, atlanır.

22344612534

e = (3,4), ağırlık 4: bul(3) = 5, bul(4) = 4.

22344612534

x ≠ y → (3,4) MST'ye eklenir, ata[5] = 4. v4 ağaca katılır; w(T) = 11.

22344612534

agac.size() = 4 = V − 1: döngü biter. (1,4)=6 hiç incelenmez. w(T) = 11.

void kruskal(int V, List<Kenar> ke) {
  Collections.sort(ke);         // artan
  int[] ata = new int[V + 1];
  for (int i = 1; i <= V; i++) ata[i] = i;
  List<Kenar> agac = new ArrayList<>();
  int k = 0;
  while (agac.size() < V - 1) {
    Kenar e = ke.get(k++);
    int x = bul(ata, e.u);
    int y = bul(ata, e.v);
    if (x != y) {               // ayrı ağaç
      agac.add(e);
      ata[x] = y;               // birleştir
    }
  }
}

Kruskal

Kruskal Örneği: Dokuz Düğüm

EF1CF1DE2FH3AB4EH5GI5DG6AC7BD9EG10BC11HI12EI15BF2047119201126101553512ABCDEFGHIKümeler: tek düğümlüler · Ağırlık: 0 · Bağlı: HAYIR

Kenarlar sıralı: 1, 1, 2, 3, 4, 5, 5, 6, 7, 9, 10, 11, 12, 15, 20. Henüz hiçbir kenar seçilmedi.

EF1CF1DE2FH3AB4EH5GI5DG6AC7BD9EG10BC11HI12EI15BF2047119201126101553512ABCDEFGHIKümeler: {E, F} · Ağırlık: 1 · Bağlı: HAYIR

EF = 1 eklendi (iki farklı küme). Toplam ağırlık 1.

EF1CF1DE2FH3AB4EH5GI5DG6AC7BD9EG10BC11HI12EI15BF2047119201126101553512ABCDEFGHIKümeler: {C, E, F} · Ağırlık: 2 · Bağlı: HAYIR

CF = 1 eklendi (iki farklı küme). Toplam ağırlık 2.

EF1CF1DE2FH3AB4EH5GI5DG6AC7BD9EG10BC11HI12EI15BF2047119201126101553512ABCDEFGHIKümeler: {C, D, E, F} · Ağırlık: 4 · Bağlı: HAYIR

DE = 2 eklendi (iki farklı küme). Toplam ağırlık 4.

EF1CF1DE2FH3AB4EH5GI5DG6AC7BD9EG10BC11HI12EI15BF2047119201126101553512ABCDEFGHIKümeler: {C, D, E, F, H} · Ağırlık: 7 · Bağlı: HAYIR

FH = 3 eklendi (iki farklı küme). Toplam ağırlık 7.

EF1CF1DE2FH3AB4EH5GI5DG6AC7BD9EG10BC11HI12EI15BF2047119201126101553512ABCDEFGHIKümeler: {C, D, E, F, H} {A, B} · Ağırlık: 11 · Bağlı: HAYIR

AB = 4 eklendi (iki farklı küme). Toplam ağırlık 11.

EF1CF1DE2FH3AB4EH5GI5DG6AC7BD9EG10BC11HI12EI15BF2047119201126101553512ABCDEFGHIKümeler: {C, D, E, F, H} {A, B} · Ağırlık: 11 · Bağlı: HAYIR

EH = 5: E ve H zaten aynı kümede (E–F–H yolu) → döngü, eklenmez. Toplam 11 kalır.

EF1CF1DE2FH3AB4EH5GI5DG6AC7BD9EG10BC11HI12EI15BF2047119201126101553512ABCDEFGHIKümeler: {C, D, E, F, H} {A, B} {G, I} · Ağırlık: 16 · Bağlı: HAYIR

GI = 5 eklendi (iki farklı küme). Toplam ağırlık 16.

EF1CF1DE2FH3AB4EH5GI5DG6AC7BD9EG10BC11HI12EI15BF2047119201126101553512ABCDEFGHIKümeler: {C, D, E, F, G, H, I} {A, B} · Ağırlık: 22 · Bağlı: HAYIR

DG = 6 eklendi (iki farklı küme). Toplam ağırlık 22.

EF1CF1DE2FH3AB4EH5GI5DG6AC7BD9EG10BC11HI12EI15BF2047119201126101553512ABCDEFGHIKümeler: {A, B, C, D, E, F, G, H, I} · Ağırlık: 29 · Bağlı: EVET

AC = 7 eklendi (iki farklı küme). Toplam ağırlık 29. 8 = V − 1 kenar: MST = 29, çizge bağlı.

Kruskal

Kruskal: Karmaşıklık Analizi

İşlemKaç kezMaliyet
Kenarları ağırlığa göre sıralama1O(E log E)
oluştur(V)1O(V)
bul (her kenar için 2)≤ 2EO(E · α(V)) — yol kısaltma + rütbe
O(E log V) — yalnızca rütbe
birleştirV − 1
  • Toplam: O(E log E); sıralama baskındır. E ≤ V² olduğundan log E ≤ 2 log V, yani O(E log E) = O(E log V).
  • Kenarlar zaten sıralıysa (ya da ağırlıklar küçük tam sayıysa, saymalı sıralama) süre neredeyse doğrusal: O(E · α(V)).
  • Bellek: kenar listesi + ebeveyn dizisi (ata) → O(V + E).
Union-find işlemleri yalnızca rütbeye göre birleştirmeyle en kötü O(log V) sürer; yol kısaltma da eklenince işlem başına amortize maliyet O(α(V)) olur. Her iki durumda da toplamı sıralama belirler.

Prim

Prim Algoritması

  • Tüm düğümleri bağlayan en küçük ağırlıklı ağacı oluşturur; açgözlü bir algoritmadır.
  • Robert C. Prim (1957); daha önce V. Jarník (1930) bulmuş, E. W. Dijkstra (1959) yeniden keşfetmiştir.
  • Bir başlangıç düğümü seçilir; her adımda ağaçta olmayan düğümler arasından, ağaca en ucuz kenarla bağlanan düğüm ağaca eklenir.
  • Her an tek bir ağaç vardır (Kruskal'daki ormandan farklı olarak).
236471sabcdkesimi geçen en ucuz kenar: 4

Güçlü yönler

  • Yoğun çizgelerde uygun: matrisle O(V²).
  • Kenar sıralaması gerekmez.
  • Komşuluk listesi/matrisi ile doğal çalışır.

Zayıf yönler

  • Performans veri yapısına bağlı (dizi, ikili heap, Fibonacci heap).
  • Bağlı olmayan çizgede yalnızca başlangıcın bileşenini kapsar.

Prim

Prim: Adımlar, Anahtar ve Ebeveyn

  1. Başlangıç düğümü seçilir ve bu düğüme ait tüm kenarlar öncelikli kuyruğa eklenir.
  2. Kuyruktan, ağaçta olmayan bir düğüme giden en küçük ağırlıklı kenar seçilir.
  3. Seçilen kenar ile bağlantılı yeni düğüm ağaca eklenir.
  4. Yeni düğüme bağlı kenarlar kuyruğa eklenir; tüm düğümler ağaca girene kadar 2–4 tekrarlanır.
anahtar[v] (key)v'yi ağaca bağlayan şimdiye kadarki en ucuz kenarın ağırlığı. Başta ∞, kaynakta 0.
ata[v]: ebeveyn (π, parent)Bu en ucuz kenarın ağaçtaki ucu. Sonunda (ata[v], v) kenarları MST'yi verir.

Kuyruktan çıkan düğüm için, ağaçta olmayan her komşu v'de: ağırlık(u, v) < anahtar[v] ise anahtar ve ebeveyn güncellenir.

Prim

Prim: Sözde Kod

PRIM(G, kaynak):
  MST = [ ]
  mesafeler = [ ]
  ata = [ ]
  ziyaretEdildi = [ ]
  her bir v için V içinde:
    mesafeler[v] = ∞
    ziyaretEdildi[v] = 0
  mesafeler[kaynak] = 0
  öncelikKuyruğu.ekle(kaynak, 0)
döngü öncelikKuyruğu boş değil iken:
  u = öncelikKuyruğu.çıkar()
  eğer ziyaretEdildi[u] == 0:
    ziyaretEdildi[u] = 1
    her bir (u, v, ağırlık) için G[u] içinde:
      eğer ziyaretEdildi[v] == 0 ve
           ağırlık < mesafeler[v]:
        mesafeler[v] = ağırlık
        ata[v] = u
        öncelikKuyruğu.ekle(v, ağırlık)
her bir v için V içinde (kaynak hariç):
  MST.ekle((ata[v], v, mesafeler[v]))
döndür MST

Bu "tembel" (lazy) sürüm bir düğümü kuyruğa birden çok kez ekleyebilir; ziyaretEdildi denetimi eski kayıtları atar. Kuyruk en fazla E kayıt tutar → O(E log E).

Prim

Prim Adım Adım: Öncelikli Kuyruk

22344612534
keyuπ
01/
∞2/
∞3/
∞4/
∞5/

w(T) = 0

İlklendirme: kuyruk Q tüm düğümlerle başlatılır; key(1) = 0, diğerleri ∞, π = /.

22344612534
keyuπ
231
321
641
∞5/

w(T) = 0

Kuyruktan düğüm 1 çıkar. Komşular güncellenir: key(3) = 2 (1,3), key(2) = 3 (1,2), key(4) = 6 (1,4).

22344612534
keyuπ
321
443
∞5/

w(T) = 2

Düğüm 3 çıkar, T'ye (1,3) eklenir. key(4) = 4 (3,4) olur; (2,3) = 4 > key(2) = 3 → değişmez.

22344612534
keyuπ
252
443

w(T) = 5

Düğüm 2 çıkar, T'ye (1,2) eklenir. key(5) = 2 (2,5).

22344612534
keyuπ
443

w(T) = 7

Düğüm 5 çıkar, T'ye (2,5) eklenir. Ağaçta olmayan komşusu yok: Q'da güncelleme yok.

22344612534
keyuπ
Q = ∅

w(T) = 11

Düğüm 4 çıkar, T'ye (3,4) eklenir. Q'da güncelleme yok.

22344612534
keyuπ
Q = ∅

w(T) = 11

Son durum: Q = ∅. MST = (1,3), (1,2), (2,5), (3,4), w(T) = 11 — Kruskal ile aynı ağaç.

Kesikli çizgi: π ile gösterilen, henüz kesinleşmemiş en ucuz bağlantı. Q tablosu key değerine göre sıralıdır.

Prim · Kodu adım adım çalıştır

Prim: Kodu Adım Adım İzle (Komşuluk Matrisi)

1332654432ABCDEF

A–F çizgesi, kaynak B (indis 1). Tüm anahtarlar ∞; anahtar[B] = 0, ata[B] = −1.

1332654432ABCDEF

enKucukAnahtar → u = B (anahtar 0): kaynak ağaca girer.

1332654432ABCDEF

v = A: G[B][A] = 1 < anahtar[A] = ∞ → anahtar[A] = 1, ata[A] = B.

1332654432ABCDEF

v = C: G[B][C] = 3 < anahtar[C] = ∞ → anahtar[C] = 3, ata[C] = B.

1332654432ABCDEF

v = D: G[B][D] = 2 < anahtar[D] = ∞ → anahtar[D] = 2, ata[D] = B.

1332654432ABCDEF

v = E: G[B][E] = 6 < anahtar[E] = ∞ → anahtar[E] = 6, ata[E] = B.

1332654432ABCDEF

v = F: G[B][F] = 5 < anahtar[F] = ∞ → anahtar[F] = 5, ata[F] = B.

1332654432ABCDEF

enKucukAnahtar → u = A (anahtar 1); (B,A) ağaca girer. w(T) = 1. AD = 3 > anahtar[D] = 2: güncelleme yok.

1332654432ABCDEF

enKucukAnahtar → u = D (anahtar 2); (B,D) ağaca girer. w(T) = 3.

1332654432ABCDEF

v = E: G[D][E] = 3 < anahtar[E] = 6 → anahtar[E] = 3, ata[E] = D.

1332654432ABCDEF

enKucukAnahtar → u = C (anahtar 3); (B,C) ağaca girer. w(T) = 6. C ve E eşit (3): küçük indisli C.

1332654432ABCDEF

v = F: G[C][F] = 4 < anahtar[F] = 5 → anahtar[F] = 4, ata[F] = C.

1332654432ABCDEF

enKucukAnahtar → u = E (anahtar 3); (D,E) ağaca girer. w(T) = 9.

1332654432ABCDEF

v = F: G[E][F] = 2 < anahtar[F] = 4 → anahtar[F] = 2, ata[F] = E.

1332654432ABCDEF

Döngü V − 1 = 5 kez döndü; son düğüm F'nin ebeveyni E. MST = (ata[v], v): AB, BC, BD, DE, EF → w(T) = 11.

void prim(int[][] G, int kaynak) {
  int V = G.length;
  int[] anahtar = new int[V];
  int[] ata = new int[V];
  boolean[] agacta = new boolean[V];
  Arrays.fill(anahtar, Integer.MAX_VALUE);
  anahtar[kaynak] = 0;
  ata[kaynak] = -1;
  for (int s = 0; s < V - 1; s++) {
    int u = enKucukAnahtar(anahtar, agacta);
    agacta[u] = true;
    for (int v = 0; v < V; v++)
      if (G[u][v] != 0 && !agacta[v]
          && G[u][v] < anahtar[v]) {
        anahtar[v] = G[u][v];
        ata[v] = u;
      }
  }
}

Prim · Kodu adım adım çalıştır

Prim: Tembel Öncelikli Kuyruk Sürümünü İzle

22344612534pq(1,0)

Beş düğümlü yönsüz çizge, kaynak 1. anahtar[1] = 0, diğerleri ∞; kuyrukta tek kayıt (düğüm, anahtar) = (1,0). Ebeveyn dizisinde (ata[]) − henüz atanmadı demek.

22344612534pq(3,2)(2,3)(4,6)

(1,0) en küçük kayıt: 1 ağaca girer. anahtar[2]: ∞ → 3, anahtar[3]: ∞ → 2, anahtar[4]: ∞ → 6; yeni kayıtlar kuyruğa eklendi.

22344612534pq(2,3)(4,4)(4,6)

(3,2) en küçük kayıt: 3 ağaca girer (kenar 1–3, ağırlık 2). anahtar[4]: 6 → 4; yeni kayıtlar kuyruğa eklendi. 2'ye 4'lük kenar, mevcut 3'ten pahalı: güncelleme yok. (4,6) kaydı kuyrukta kalır.

22344612534pq(5,2)(4,4)(4,6)

(2,3) en küçük kayıt: 2 ağaca girer (kenar 1–2, ağırlık 3). anahtar[5]: ∞ → 2; yeni kayıtlar kuyruğa eklendi.

22344612534pq(4,4)(4,6)

(5,2) en küçük kayıt: 5 ağaca girer (kenar 2–5, ağırlık 2). Ağaçta olmayan hiçbir komşusunun anahtarı küçülmedi.

22344612534pq(4,6)

(4,4) en küçük kayıt: 4 ağaca girer (kenar 3–4, ağırlık 4). Ağaçta olmayan hiçbir komşusunun anahtarı küçülmedi.

22344612534pq

(4,6) çıkarıldı ama 4 zaten ağaçta: bu eski kayıt, continue ile atlanır (tembel silme).

22344612534pq

Kuyruk boşaldı. MST kenarları (ata[v], v): 1–3 (2), 1–2 (3), 2–5 (2), 3–4 (4); toplam 11.

void primPQ(int kaynak) {
  Arrays.fill(anahtar, SONSUZ);
  anahtar[kaynak] = 0;
  PriorityQueue<int[]> pq =
      new PriorityQueue<>((a, b) -> a[1] - b[1]);
  pq.add(new int[] { kaynak, 0 });
  while (!pq.isEmpty()) {
    int u = pq.poll()[0];
    if (agacta[u]) continue;  // eski
    agacta[u] = true;
    for (Kenar k : komsu.get(u))
      if (!agacta[k.v] && k.w < anahtar[k.v]) {
        anahtar[k.v] = k.w; ata[k.v] = u;
        pq.add(new int[] { k.v, k.w });
      }
  }
}

Prim

Prim Örneği: Dokuz Düğüm (A'dan Başla)

47119201126101553512ABCDEFGHI
ABCDEFGHI
anahtar047∞∞∞∞∞∞
ebeveyn−AA−−−−−−

Başlangıç A: komşuları B (4) ve C (7) aday olur.

47119201126101553512ABCDEFGHI
ABCDEFGHI
anahtar0479∞20∞∞∞
ebeveyn−AAB−B−−−

B ağaca girer: (A,B) = 4, toplam 4. Güncellenen: D → 9, F → 20.

47119201126101553512ABCDEFGHI
ABCDEFGHI
anahtar0479∞1∞∞∞
ebeveyn−AAB−C−−−

C ağaca girer: (A,C) = 7, toplam 11. Güncellenen: F → 1.

47119201126101553512ABCDEFGHI
ABCDEFGHI
anahtar047911∞3∞
ebeveyn−AABFC−F−

F ağaca girer: (C,F) = 1, toplam 12. Güncellenen: E → 1, H → 3.

47119201126101553512ABCDEFGHI
ABCDEFGHI
anahtar04721110315
ebeveyn−AAEFCEFE

E ağaca girer: (F,E) = 1, toplam 13. Güncellenen: D → 2, G → 10, I → 15.

47119201126101553512ABCDEFGHI
ABCDEFGHI
anahtar0472116315
ebeveyn−AAEFCDFE

D ağaca girer: (E,D) = 2, toplam 15. Güncellenen: G → 6.

47119201126101553512ABCDEFGHI
ABCDEFGHI
anahtar0472116312
ebeveyn−AAEFCDFH

H ağaca girer: (F,H) = 3, toplam 18. Güncellenen: I → 12. EH = 5 artık kullanılamaz: E ve H ikisi de ağaçta (döngü).

47119201126101553512ABCDEFGHI
ABCDEFGHI
anahtar047211635
ebeveyn−AAEFCDFG

G ağaca girer: (D,G) = 6, toplam 24. Güncellenen: I → 5.

47119201126101553512ABCDEFGHI
ABCDEFGHI
anahtar047211635
ebeveyn−AAEFCDFG

I ağaca girer: (G,I) = 5, toplam 29. Tüm düğümler ağaçta: MST = 29 (Kruskal ile aynı).

Prim

Prim: Karmaşıklık Analizi

Uygulamaen küçüğü çıkaranahtar azaltToplam
Komşuluk matrisi + dizi taraması (yukarıdaki kod)V × O(V)O(1)O(V²)
Komşuluk listesi + ikili heap (binary heap)V × O(log V)E × O(log V)O((V + E) log V)
Tembel sürüm (sözde kod): kuyrukta kenar kopyaları≤ E ekleme/çıkarma, her biri O(log E)O(E log E)
Fibonacci heapO(log V) amortizeO(1) amortizeO(E + V log V)
Yoğun çizge (E ≈ V²)Matris sürümü O(V²) en iyisidir; heap sürümü O(V² log V) olur.
Seyrek çizge (E ≈ V)Heap sürümü O(V log V); matris sürümü gereksiz yere O(V²).

Prim

Prim ile Dijkstra Arasındaki Fark

İki algoritmanın kodu neredeyse aynıdır: bir kaynaktan başlar, öncelikli kuyruktan en küçük anahtarlı düğümü çıkarır ve komşuları gevşetir. Tek fark anahtarın anlamıdır.

Prim (MST)Dijkstra (en kısa yol)
anahtar[v]v'yi ağaca bağlayan en ucuz tek kenarkaynaktan v'ye toplam yol uzunluğu
Güncellemew(u,v) < anahtar[v]uzaklik[u] + w(u,v) < uzaklik[v]
Sonuçtoplam ağırlığı en küçük ağaçen kısa yollar ağacı (SPT)
Kaynaksonucu etkilemez (aynı ağırlık)sonucu belirler
Negatif ağırlıksorun değilçalışmaz

Beş düğümlü örnekte 1'den en kısa yollar ağacı (1,4) = 6 kenarını kullanabilir; MST onun yerine (3,4) = 4'ü seçer.

Borůvka

Borůvka (Sollin) Algoritması

  • Minimum kapsayan ağacı bulan en eski algoritma: Otakar Borůvka, 1926 (Moravya elektrik ağı). Diğer adı Sollin algoritması.
  • Başlangıçta her düğüm bağımsız bir bileşendir.
  • Her turda her bileşen kendisini dışarıya bağlayan en ucuz kenarı seçer; seçilenlerin hepsi birden eklenir.
  • Bileşenler union-find ile birleştirilir; tek bileşen kalana kadar devam edilir. Bağlı çizgede |V| − 1 kenar üretir.
1429367518abcdefghtur 1: her düğüm kendi en ucuz kenarınıseçer → 8 bileşen 3 bileşene iner

Güçlü yönler

  • Bileşenlerin seçimleri birbirinden bağımsız: paralel çalışmaya çok uygun.
  • Tur sayısı en fazla ⌈log₂ V⌉.

Zayıf yönler

  • Kruskal/Prim'den daha karmaşık kodlanır.
  • Eşit ağırlıklarda tutarlı bir eşitlik bozucu (ör. kenar indisi) şart; yoksa döngü oluşabilir.

Borůvka

Borůvka: Adımlar ve Sözde Kod

  1. Başlangıçta her düğüm tek başına bir bileşen (küme) sayılır.
  2. Her bileşen için, onu başka bir bileşene bağlayan en küçük ağırlıklı kenar bulunur.
  3. Bulunan kenarların hepsi eklenir; bağladıkları bileşenler birleştirilir (aynı kenar iki kez eklenmez).
  4. Tek bileşen kalana kadar 2. ve 3. adımlar tekrarlanır.

Not: Borůvka kenarları sıralamaz; her turda tüm kenarları bir kez tarayıp bileşen başına en küçüğü tutar.

BORUVKA(G):
  MST = [ ]
  bileşenSayısı = |V|
  döngü bileşenSayısı > 1 iken:
    enUcuz = [ ]  // bileşen başına
    her bir e = (u, v, ağırlık) için E içinde:
      cu = ayrikKume.bul(u)
      cv = ayrikKume.bul(v)
      eğer cu ≠ cv:
        enUcuz[cu] = min(enUcuz[cu], e)
        enUcuz[cv] = min(enUcuz[cv], e)
    her bir (u, v, ağırlık) için enUcuz içinde:
      eğer ayrikKume.bul(u) ≠ ayrikKume.bul(v):
        MST.ekle((u, v, ağırlık))
        ayrikKume.birleştir(u, v)
        bileşenSayısı -= 1
  döndür MST

Borůvka

Borůvka Adım Adım: Altı Düğüm

154736982ABCDEF

Başlangıç: her düğüm ayrı bir bileşen (6 bileşen).

154736982ABCDEF
BileşenEn ucuz
{A}AB 1
{B}AB 1
{C}BC 5
{D}AD 4
{E}EF 2
{F}EF 2

Tur 1: her bileşen kendi en ucuz dış kenarını seçer (mavi). AB ve EF iki bileşen tarafından seçilir ama birer kez eklenir.

154736982ABCDEF

Tur 1 sonu: 4 farklı kenar eklendi (AB, BC, AD, EF), 2 bileşen kaldı: {A, B, C, D} {E, F}. Toplam 12.

154736982ABCDEF
BileşenEn ucuz
{A,B,C,D}BE 3
{E,F}BE 3

Tur 2: her bileşen kendi en ucuz dış kenarını seçer (mavi). İki bileşen de aynı kenarı seçer.

154736982ABCDEF

Tur 2 sonu: 1 farklı kenar eklendi (BE), 1 bileşen kaldı: {A, B, C, D, E, F}. Toplam 15. MST = 15 (AB, BC, AD, EF, BE).

Kruskal kenarları 1, 2, 3, 4, 5 sırasıyla tek tek ekler; Borůvka'da ise tur 1'de dört kenar aynı anda eklenir. Sonuç ağacı aynıdır.

Borůvka

Borůvka Örneği: On İki Düğüm

1367114820932181519105171116412ABCDEFGHIJKL

Başlangıç: her düğüm ayrı bir bileşen (12 bileşen).

1367114820932181519105171116412ABCDEFGHIJKL
BileşenEn ucuz
{A}AC 6
{B}BD 1
{C}AC 6
{D}BD 1
{E}EF 2
{F}EF 2
{G}GI 5
{H}GH 15
{I}GI 5
{J}JL 4
{K}GK 10
{L}JL 4

Tur 1: her bileşenin en ucuz dış kenarı (mavi).

1367114820932181519105171116412ABCDEFGHIJKL

Tur 1 sonu: 7 farklı kenar eklendi (AC, BD, EF, GI, GH, JL, GK), 5 bileşen kaldı: {G, H, I, K} {A, C} {B, D} {E, F} {J, L}. Toplam 43.

1367114820932181519105171116412ABCDEFGHIJKL
BileşenEn ucuz
{A,C}BC 7
{B,D}DF 3
{E,F}DF 3
{G,H,I,K}KL 12
{J,L}KL 12

Tur 2: her bileşenin en ucuz dış kenarı (mavi).

1367114820932181519105171116412ABCDEFGHIJKL

Tur 2 sonu: 3 farklı kenar eklendi (BC, DF, KL), 2 bileşen kaldı: {A, B, C, D, E, F} {G, H, I, J, K, L}. Toplam 65.

1367114820932181519105171116412ABCDEFGHIJKL
BileşenEn ucuz
{A,B,C,D,E,F}EJ 18
{G,H,I,J,K,L}EJ 18

Tur 3: her bileşenin en ucuz dış kenarı (mavi).

1367114820932181519105171116412ABCDEFGHIJKL

Tur 3 sonu: 1 farklı kenar eklendi (EJ), 1 bileşen kaldı: {A, B, C, D, E, F, G, H, I, J, K, L}. MST = 83, yalnızca 3 turda.

Borůvka

Borůvka: Java Kodu ve Karmaşıklık

while (bilesenSayisi > 1) {
  Kenar[] enUcuz = new Kenar[V];
  for (Kenar e : kenarlar) {        // 1) en ucuzlar
    int k1 = bul(ata, e.u), k2 = bul(ata, e.v);
    if (k1 == k2) continue;         // aynı bileşen
    if (enUcuz[k1] == null || e.w < enUcuz[k1].w)
      enUcuz[k1] = e;
    if (enUcuz[k2] == null || e.w < enUcuz[k2].w)
      enUcuz[k2] = e;
  }
  for (Kenar e : enUcuz) {          // 2) hepsini ekle
    if (e == null) continue;
    int k1 = bul(ata, e.u), k2 = bul(ata, e.v);
    if (k1 == k2) continue;         // zaten eklendi
    agac.add(e);
    ata[k1] = k2;                   // birleştir
    bilesenSayisi--;
  }
}
  • Her turda her bileşen en az bir başka bileşenle birleşir → bileşen sayısı en az yarıya iner.
  • Tur sayısı ≤ ⌈log₂ V⌉; her tur tüm kenarları bir kez tarar: O(E).
  • Toplam: O(E log V). Sıralama yapılmaz; "ağırlık sıralaması" gerekmez.
  • e.w < karşılaştırması eşitlikte ilk (küçük indisli) kenarı tutar: bu tutarlı eşitlik bozucu döngüyü önler.

Borůvka · Kodu adım adım çalıştır

Borůvka: Kodu Adım Adım İzle

154736982ABCDEF

Altı bileşen (her düğüm tek başına); kenarlar listedeki sırayla taranır. Kenar AB(1): enUcuz[A] ve enUcuz[B] = AB(1).

154736982ABCDEF

Kenar BC(5): enUcuz[C] = BC(5). Kenar AD(4): enUcuz[D] = AD(4).

154736982ABCDEF

Kenar BE(3): enUcuz[E] = BE(3).

154736982ABCDEF

BD(7) hiçbir bileşenin en ucuzunu geçemedi. Kenar BF(6): enUcuz[F] = BF(6).

154736982ABCDEF

CF(9) ve DE(8) daha ucuzların gerisinde kaldı. Kenar EF(2): enUcuz[E] ve enUcuz[F] = EF(2). E için 3'ten, F için 6'dan ucuz.

154736982ABCDEF

AB(1) ağaca eklenir; bul ile kökler A ve B → ata[A] = B. Bileşen sayısı 5.

154736982ABCDEF

enUcuz[B] = AB(1) ama iki ucu artık aynı bileşende: zaten eklendi, atlanır.

154736982ABCDEF

BC(5) ağaca eklenir; bul ile kökler B ve C → ata[B] = C. Bileşen sayısı 4.

154736982ABCDEF

AD(4) ağaca eklenir; bul ile kökler C ve D → ata[C] = D. Bileşen sayısı 3.

154736982ABCDEF

EF(2) ağaca eklenir; bul ile kökler E ve F → ata[E] = F. Bileşen sayısı 2.

154736982ABCDEF

enUcuz[F] = EF(2) ama iki ucu artık aynı bileşende: zaten eklendi, atlanır.

154736982ABCDEF

Tur 2: AB, BC, AD, BD, EF bileşen içinde kalır (continue). Bileşenler arası BE(3), BF(6), CF(9), DE(8) içinden en ucuzu BE(3): iki kökün enUcuz'u da BE.

154736982ABCDEF

BE(3) ağaca eklenir; bul ile kökler D ve F → ata[D] = F. Bileşen sayısı 1. Tek bileşen kaldı.

154736982ABCDEF

enUcuz[F] = BE(3) ama iki ucu artık aynı bileşende: zaten eklendi, atlanır. bilesenSayisi = 1: döngü biter, MST ağırlığı 15.

while (bilesenSayisi > 1) {
  Kenar[] enUcuz = new Kenar[V];
  for (Kenar e : kenarlar) {     // 1) en ucuzlar
    int k1 = bul(ata, e.u), k2 = bul(ata, e.v);
    if (k1 == k2) continue;
    if (enUcuz[k1] == null || e.w < enUcuz[k1].w)
      enUcuz[k1] = e;
    if (enUcuz[k2] == null || e.w < enUcuz[k2].w)
      enUcuz[k2] = e;
  }
  for (Kenar e : enUcuz) {       // 2) hepsini ekle
    if (e == null) continue;
    int k1 = bul(ata, e.u), k2 = bul(ata, e.v);
    if (k1 == k2) continue;
    agac.add(e);
    ata[k1] = k2;           // birleştir
    bilesenSayisi--;
  }
}

Ters Silme

Ters Silme (Reverse-Delete) Algoritması

  • Minimum kapsayan ağacı bulan açgözlü bir algoritmadır (Kruskal, 1956 makalesinde önerdi).
  • Kenarları ağırlıklarına göre azalan şekilde sıralar.
  • En ağır kenardan başlayarak, çizgenin bağlılığını bozmayan her kenarı siler.
  • Döngü özelliğine dayanır: silinen kenar, bir döngünün en ağır kenarıdır.
Kruskal'ın aynasıKruskal küçük kenarları eklerken, ters silme büyük kenarları silmeye çalışır. Biri boş çizgeden, öteki tam çizgeden başlar.
349abc
KullanımDaha çok teorik/öğretici değeri vardır; her silmede bağlılık testi gerektiği için pratikte genellikle yavaştır.

Ters Silme

Ters Silme: Adımlar, Sözde Kod, Karmaşıklık

  1. Tüm kenarlar ağırlığına göre azalan şekilde sıralanır.
  2. Sıradaki en ağır kenar silinir.
  3. Çizge artık bağlı değilse silinen kenar geri eklenir.
  4. Tüm kenarlar işlenene kadar 2. ve 3. adımlar tekrarlanır.
Karmaşıklık: her kenar için bir BFS/DFS (ya da union-find ile yeniden kurma) → O(E · (V + E)). Sıralamanın O(E log E) maliyeti bunun yanında küçük kalır.
TERS_SİLME(G):
  MST = tüm kenarlar
  kenarlar.sırala(azalana göre)
  her bir (u, v, ağırlık) için kenarlar içinde:
    MST.sil((u, v, ağırlık))
    ayrikKume.sıfırla()
    her bir (x, y) için MST içinde:
      ayrikKume.birleştir(x, y)
    kök = ayrikKume.bul(V[0])
    eğer bir v için ayrikKume.bul(v) ≠ kök:
      MST.ekle((u, v, ağırlık))  // geri koy
  döndür MST

Bağlılık testi tüm düğümlere bakar; kökten kopuk en az bir düğüm varsa silinen kenar bir kez geri konur.

Ters Silme

Ters Silme Adım Adım: Yedi Düğüm

58911871596752465130
KenarwDurum
3–415
5–611
1–39
4–69
1–28
4–58
1–47
0–17
3–56
2–45
0–35

Kenarlar azalan sırada: 15, 11, 9, 9, 8, 8, 7, 7, 6, 5, 5. Toplam ağırlık 90.

58911871596752465130
KenarwDurum
3–415silindi
5–611
1–39
4–69
1–28
4–58
1–47
0–17
3–56
2–45
0–35

3–4 = 15 silinir: çizge hâlâ bağlı (kenar bir döngünün en ağırıdır).

58911871596752465130
KenarwDurum
3–415silindi
5–611silindi
1–39
4–69
1–28
4–58
1–47
0–17
3–56
2–45
0–35

5–6 = 11 silinir: çizge hâlâ bağlı (kenar bir döngünün en ağırıdır).

58911871596752465130
KenarwDurum
3–415silindi
5–611silindi
1–39silindi
4–69
1–28
4–58
1–47
0–17
3–56
2–45
0–35

1–3 = 9 silinir: çizge hâlâ bağlı (kenar bir döngünün en ağırıdır).

58911871596752465130
KenarwDurum
3–415silindi
5–611silindi
1–39silindi
4–69kaldı
1–28
4–58
1–47
0–17
3–56
2–45
0–35

4–6 = 9 silinirse düğüm 6 yalnız kalır → bağlılık bozulur, kenar geri eklenir.

58911871596752465130
KenarwDurum
3–415silindi
5–611silindi
1–39silindi
4–69kaldı
1–28silindi
4–58
1–47
0–17
3–56
2–45
0–35

1–2 = 8 silinir: çizge hâlâ bağlı (kenar bir döngünün en ağırıdır).

58911871596752465130
KenarwDurum
3–415silindi
5–611silindi
1–39silindi
4–69kaldı
1–28silindi
4–58silindi
1–47
0–17
3–56
2–45
0–35

4–5 = 8 silinir: çizge hâlâ bağlı (kenar bir döngünün en ağırıdır).

58911871596752465130
KenarwDurum
3–415silindi
5–611silindi
1–39silindi
4–69kaldı
1–28silindi
4–58silindi
1–47kaldı
0–17kaldı
3–56kaldı
2–45kaldı
0–35kaldı

Kalan 6 kenar (7, 7, 6, 5, 5 ve 9) birer köprüdür: hiçbiri silinemez. 6 = V − 1 kenar, MST = 39.

Ters Silme · Kodu adım adım çalıştır

Ters Silme: Kodu Adım Adım İzle

7589751568911ABCDEFG

Kenarlar azalan sıralanır: DE 15, FG 11, BD 9, EG 9, BC 8, EF 8, AB 7, BE 7, DF 6, AD 5, CE 5.

7589751568911ABCDEFG

En yüksek ağırlıklı DE incelenir: DE = 15 silindi, bagliMi = true → silinmiş kalır.

7589751568911ABCDEFG

FG çıkarılırsa bağlılık bozuluyor mu? FG = 11 silindi, bagliMi = true → silinmiş kalır.

7589751568911ABCDEFG

Bir sonraki en ağır kenar BD: BD = 9 silindi, bagliMi = true → silinmiş kalır.

7589751568911ABCDEFG

EG = 9 silinirse G yalnız kalır (FG zaten silindi) → bagliMi = false, EG geri konur; i = 1.

7589751568911ABCDEFG

BC = 8 silindi, bagliMi = true → silinmiş kalır.

7589751568911ABCDEFG

EF = 8 silindi, bagliMi = true → silinmiş kalır.

7589751568911ABCDEFG

AB = 7 silinirse {A, D, F} kopar → geri konur, i = 2.

7589751568911ABCDEFG

BE = 7 silinirse {C, E, G} kopar → geri konur, i = 3.

7589751568911ABCDEFG

DF = 6 silinirse {F} kopar → geri konur, i = 4.

7589751568911ABCDEFG

AD = 5 silinirse {D, F} kopar → geri konur, i = 5.

7589751568911ABCDEFG

CE = 5 silinirse {C} kopar → geri konur, i = 6.

7589751568911ABCDEFG

i = boyut = 6: döngü biter. Silinecek başka kenar yok; kalan ağaç AB, AD, BE, CE, DF, EG → w = 39.

void tersSil(int V, List<Kenar> ke) {
  ke.sort((a, b) -> b.w - a.w); // azalan
  int i = 0;
  while (i < ke.size()) {
    Kenar e = ke.remove(i);     // geçici sil
    if (!bagliMi(V, ke)) {
      ke.add(i, e);             // geri koy
      i++;
    }
  }
}

Karşılaştırma

Dört Algoritmanın Karşılaştırması

KruskalPrimBorůvkaTers silme
Bakışkenar odaklıdüğüm odaklıbileşen odaklıkenar odaklı (silme)
Ara durumormantek ağaçormanbağlı çizge
Dayandığı özellikkesimkesimkesimdöngü
Veri yapısısıralı kenarlar + union-findöncelikli kuyruk / diziunion-findBFS/DFS
ZamanO(E log E)O(V²) ya da O((V + E) log V)O(E log V)O(E · (V + E))
En uygunseyrek çizgeyoğun çizgeparalel / dağıtıköğretim, teori
Bağlı olmayan çizgeorman verirbir bileşenorman verirbileşenleri korur
Dokuz düğümlü çizgede Kruskal ve Prim aynı ağacı (29) bulur; ekleme sırası farklıdır: Kruskal 1, 1, 2, 3, 4, 5, 6, 7 — Prim 4, 7, 1, 1, 2, 3, 6, 5.

Özet

Özet

KonuHatırlanacaklar
MSTbağlı, yönsüz, ağırlıklı çizgede toplam ağırlığı en küçük kapsayan ağaç; V − 1 kenar
Özelliklerkesimin en hafif kenarı güvenli; döngünün en ağır kenarı dışarıda; farklı ağırlıklar → tek MST
Kruskalkenarlar sıralanır; bul(u) ≠ bul(v) ise kenar eklenir, ağaçlar birleşir — O(E log E)
Union-Findata[] ormanı; yol kısaltma + rütbe → işlem başına O(α(V))
Primtek ağacı büyüt; anahtar = ağaca en ucuz kenar — O(V²) / O((V + E) log V)
Borůvkaher bileşen en ucuz dış kenarını aynı anda ekler; ≤ log₂ V tur — O(E log V)
Ters silmeazalan sırada sil, bağlılık bozulursa geri koy — O(E · (V + E))

Özet

Etkileşimli Simülatörler

Minimum Kapsayan Ağaç2–15 düğümlü rastgele, bağlı ve ağırlıklı çizgelerde (düğümler sürüklenebilir) Prim (düğüm 0'dan) ve Kruskal adım adım: eklenen ve döngü yüzünden atlanan kenarlar günlükte listelenir, sonunda toplam ağırlık gösterilir.
Prim ve KruskalAynı çizgede iki algoritmanın bulduğu toplam ağırlık aynıdır, kenar ekleme sırası farklıdır. Ağırlıkları eşit kenarlar varsa iki ağaç farklı olabilir.

Özet

Sık Yapılan Hatalar

MST'yi en kısa yol ağacı sanmakMST toplam ağırlığı küçültür; iki düğüm arasındaki MST yolu en kısa yol olmak zorunda değildir.
Döngüyü komşulukla denetlemekKruskal'da "u ile v doğrudan bağlı mı?" yetmez; aynı bileşende mi sorusu (bul) sorulmalıdır.
Prim'de uzaklık toplamakanahtar[u] + w yazmak Dijkstra'dır. Prim'de anahtar yalnızca tek kenarın ağırlığıdır.
Negatif ağırlıktan korkmakMST algoritmaları negatif ağırlıkla da doğru çalışır (yalnızca karşılaştırma yapılır); sorun Dijkstra'ya özgüdür.
Bağlı olmayan çizgeMST yoktur, minimum kapsayan orman vardır. while (agac.size() < V − 1) kenarlar bitince dizi sınırını aşar.
Yönlü çizgeye uygulamakBu algoritmalar yönsüz çizge içindir. Yönlü karşılığı (minimum kapsayan dallanma) Chu–Liu/Edmonds algoritmasıdır.

Özet

Örnek Problemler

Çizge: AB = 2, AC = 3, BC = 1, BD = 4, CD = 5, CE = 6, DE = 7 (yönsüz).

  1. Kruskal'ın incelediği kenarları sırasıyla yazın; hangileri reddedilir? w(T) = ?
  2. Prim'i A'dan çalıştırın: düğümler hangi sırayla ağaca girer? İlk adımdan sonra anahtar dizisi nedir?
  3. Borůvka kaç turda biter? Tur 1'de hangi kenarlar seçilir?
  4. Ters silme hangi kenarları siler?
  5. 100 düğümlü bağlı bir çizgenin MST'sinde kaç kenar vardır?
  6. Tüm ağırlıklara 5 eklenirse MST değişir mi? Toplam ne olur?
Cevapları göster
  1. BC 1 ✓, AB 2 ✓, AC 3 ✗ (döngü), BD 4 ✓, CD 5 ✗, CE 6 ✓ → 4 kenar, w(T) = 13. DE incelenmez.
  2. A, B (2), C (1, B üzerinden), D (4), E (6). A'dan sonra: anahtar[B] = 2, [C] = 3, [D] = [E] = ∞.
  3. 1 tur: A→AB, B→BC, C→BC, D→BD, E→CE; dört farklı kenar tek bileşen yapar.
  4. DE 7 silinir, CE 6 kalır (E kopar), CD 5 silinir, BD 4 kalır, AC 3 silinir, AB ve BC kalır.
  5. V − 1 = 99.
  6. Değişmez: kenarların sırası korunur. Toplam 13 + 4 · 5 = 33 olur.

Özet

Alıştırmalar

  1. Tüm ağırlıklar farklıysa MST'nin tek olduğunu kesim özelliğiyle gösterin.
  2. En büyük kapsayan ağacı bulmak için Kruskal'ı nasıl değiştirirsiniz?
  3. Dokuz düğümlü örneğin MST'sini kullanarak düğümleri 3 kümeye ayırın.
  4. 0..5, ata[bul(x)] = bul(y): birleştir (0,1), (2,3), (1,3), (4,5), (3,5). Son ata? bul(0) neyi değiştirir?
  5. V = 1000: Prim O(V²) ve O(E log V) sürümlerini E = 5 000 ve 500 000 için karşılaştırın.
  6. Kruskal'ı bağlı olmayan çizgede orman döndürecek biçimde düzeltin.
Cevaplar / ipuçları
  1. Her MST kenarı e, T − e'nin tanımladığı kesimin tek en hafif kenarıdır; o kenar her MST'de olmak zorunda → MST'ler aynı.
  2. Kenarlar azalan sırayla işlenir (ya da −w kullanılır).
  3. MST'den en ağır 2 kenar (AC 7, DG 6) silinir: {C, D, E, F, H} {A, B} {G, I}.
  4. ata = [1, 3, 3, 5, 5, 5]. bul(0): 0→1→3→5 yolu sıkışır → ata = [5, 5, 3, 5, 5, 5].
  5. V² = 10⁶; E log V ≈ 5 · 10⁴ (heap kazanır) ve ≈ 5 · 10⁶ (matris kazanır).
  6. Koşul: k < ke.size() && agac.size() < V − 1; sonda agac.size() < V − 1 ise çizge bağlı değildir.

Özet

Kaynaklar

  • Cormen, Leiserson, Rivest ve Stein, Introduction to Algorithms, 4. baskı, MIT Press, 2022 (Bölüm 19: ayrık kümeler, Bölüm 21: MST).
  • Sedgewick ve Wayne, Algorithms, 4. baskı, Addison-Wesley, 2011 (Bölüm 4.3: Minimum Spanning Trees).
  • J. B. Kruskal, "On the Shortest Spanning Subtree of a Graph and the Traveling Salesman Problem", Proc. AMS 7(1), 1956.
  • R. C. Prim, "Shortest Connection Networks and Some Generalizations", Bell System Technical Journal 36(6), 1957.
  • O. Borůvka, "O jistém problému minimálním", Práce Moravské přírodovědecké společnosti 3, 1926.
  • R. E. Tarjan, "Efficiency of a Good But Not Linear Set Union Algorithm", Journal of the ACM 22(2), 1975.

Son

Bölüm 4.3: Minimum Kapsayan Ağaç Algoritmaları
Sonraki bölüm: Bölüm 4.4: Ağ Akışı · Terim sözlüğü
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.