SEN2212 · 13. hafta · Analyzing and implementing greedy algorithms. Quiz.

Minimum yayılan ağaç: Prim, Kruskal ve union-find

Ağırlıklı yönsüz grafta tüm düğümleri en ucuza bağlayan ağaç. Kruskal'ı union-find ile, Prim'i adım tablosuyla izlemeyi ve quiz tipi soruları çözmeyi öğrenirsin.

minimum spanning tree (MST)spanning treecut propertycycle propertyPrim's algorithmKruskal's algorithmunion-find (disjoint set)findunion by sizeunion by rankpath compressionconnected component

Bir kampüse kablo çekiyorsun. Her bina çifti arasında bir maliyet var. Bütün binaları birbirine bağlamak istiyorsun ama en az kabloyla. Cevap minimum yayılan ağaçtır (minimum spanning tree, MST): tüm düğümleri içeren, döngüsüz, toplam ağırlığı en küçük kenar kümesi. Bu haftanın iki algoritması da greedy’dir. Sınav ve quiz soruları neredeyse hep iz sorusudur: “Kruskal’ın kabul ettiği kenarları sırayla yaz”, “Prim’i A’dan başlat, sırayı ver”, “MST ağırlığı kaç?”, “union-find dizisini göster”.

Altın kurallar:

  1. MST’de tam V − 1 kenar vardır. Daha azı bağlamaz, daha fazlası döngü kurar.
  2. Kruskal kenar seçer: en hafif kenardan başla, döngü kurmuyorsa al.
  3. Prim düğüm büyütür: tek ağaç, her adımda ona en ucuz bağlanan düğümü ekle.
  4. Prim’in tablosu Dijkstra’ya benzer ama yol toplamı tutmaz, sadece tek kenarın ağırlığını tutar.
  5. Döngü kontrolü union-find ile yapılır: iki uç aynı kümedeyse red.

Tanım ve iki özellik

Yayılan ağaç (spanning tree): bağlı, yönsüz bir grafın tüm düğümlerini içeren ve döngüsü olmayan alt grafı. V düğüm için V−1 kenar. Minimum olanı, kenar ağırlıkları toplamı en küçük olandır.

Bütün MST algoritmalarının doğruluğu iki özelliğe dayanır:

  • Kesim özelliği (cut property): Düğümleri herhangi iki gruba ayır. İki grup arasında geçen kenarlardan en hafifi (eşsizse) her MST’de yer alır.
  • Döngü özelliği (cycle property): Bir döngüdeki en ağır kenar (eşsizse) hiçbir MST’de yer almaz.

Prim kesim özelliğini doğrudan kullanır (kesim = ağaç / geri kalanı). Kruskal, reddettiği her kenarın bir döngünün en ağır kenarı olduğunu kullanır.

Çalışma grafı

G grafı (yönsüz). Kenarlar ağırlığa göre sıralı:

kenar  ağırlık      kenar  ağırlık
A-C    1            B-C    7
C-D    2            C-E    8
A-B    3            D-F    9
D-E    4            B-E    10
B-D    5
E-F    6

Kruskal algoritması

  1. Kenarları ağırlığa göre artan sırala (eşitlikte listeleme sırası).
  2. Her düğüm kendi kümesinde başlar.
  3. Sıradaki kenar (u, v): find(u) != find(v) ise kenarı al ve union(u, v). Değilse reddet (döngü kurar).
  4. V−1 kenar alınca dur.
kenar  karar   kümeler sonrası
A-C 1  KABUL   {A,C} {B} {D} {E} {F}
C-D 2  KABUL   {A,C,D} {B} {E} {F}
A-B 3  KABUL   {A,B,C,D} {E} {F}
D-E 4  KABUL   {A,B,C,D,E} {F}
B-D 5  RED     B ve D aynı kümede
E-F 6  KABUL   {A,B,C,D,E,F} → 5 kenar, dur

Programın parent dizisi (A..F sırasıyla, her eleman o düğümün ebeveyni):

  A-C 1 ACCEPT parent [A B A D E F]
  C-D 2 ACCEPT parent [A B A A E F]
  A-B 3 ACCEPT parent [A A A A E F]
  D-E 4 ACCEPT parent [A A A A A F]
  B-D 5 reject parent [A A A A A F]
  E-F 6 ACCEPT parent [A A A A A A]
Kruskal total 16 edges 5

MST:

    B
    | 3
    A
    | 1
    C
    | 2
    D
    | 4
    E
    | 6
    F

Bu örnekte MST bir zincir çıktı; her zaman böyle olmaz.

TUZAK · kalan kenarları da kontrol etmeye çalışmak. 5. kenar alındığında dur. B-C 7, C-E 8 gibi kenarlar zaten döngü kurar; sınavda tabloyu gereksiz uzatıp zaman kaybetme. Ama soru “list all rejected edges” diyorsa kalanları da red olarak yaz.

Union-find (disjoint set)

Kruskal’ın döngü kontrolü bu yapıyla hızlanır. Her küme bir ağaçtır; parent[x] x’in ebeveynidir, kökte parent[r] = r.

  • find(x): köke kadar çık, kökü döndür.
  • union(a, b): iki kökü bul, birini diğerinin altına bağla.

İki iyileştirme:

  • Union by size (ya da rank): küçük ağacın kökünü büyüğün altına bağla. Ağaç yüksekliği O(log⁡n)O(\log n)‘i geçmez.
  • Path compression: find sırasında yoldaki her düğümü doğrudan köke bağla. Sonraki find’lar tek adım.

İkisi birlikte işlem başına pratikte sabit süre verir (O(α(n))O(\alpha(n)), ters Ackermann).

İz: 0..7 üzerinde union by size

Kural: boyutlar eşitse ikinci argümanın kökü birincinin altına girer.

  union(0,1) parent [0, 0, 2, 3, 4, 5, 6, 7]
  union(2,3) parent [0, 0, 2, 2, 4, 5, 6, 7]
  union(4,5) parent [0, 0, 2, 2, 4, 4, 6, 7]
  union(6,7) parent [0, 0, 2, 2, 4, 4, 6, 6]
  union(0,2) parent [0, 0, 0, 2, 4, 4, 6, 6]
  union(4,6) parent [0, 0, 0, 2, 4, 4, 4, 6]
  union(0,4) parent [0, 0, 0, 2, 0, 4, 4, 6]
     önce                 find(7) sonrası
       0                       0
     / | \                / / | \ \
    1  2  4              1 2  4  6 7
       |  | \              |  |
       3  5  6             3  5
             |
             7
  path from 7 before find: 7 6 4 0
  find(7) = 0 parent after [0, 0, 0, 2, 0, 4, 0, 0]

TUZAK · path compression sadece yoldakileri değiştirir. find(7) sonrası 6 ve 7 köke bağlandı. 3 ve 5 yolda değildi, ebeveynleri (2 ve 4) değişmedi.

Prim algoritması

  1. Başlangıç düğümünün değeri 0, diğerleri ∞.
  2. Ağaçta olmayanlar içinden değeri en küçük düğümü seç, ağaca ekle (eşitlikte küçük etiket).
  3. Yeni düğümün her komşusu u için: w(v,u) < d[u] ise d[u] = w(v,u), from[u] = v.
  4. Tüm düğümler eklenene kadar tekrar et.

Dijkstra’dan tek fark 3. adımda: Dijkstra d[v] + w karşılaştırır, Prim sadece w. Prim’in d[u] değeri “u’yu ağaca bağlamanın en ucuz kenarı”dır, kaynaktan uzaklık değil.

G’de A’dan başla (* ağaçta):

ekle  A   B   C   D   E   F    kenar
A     0*  3   1   ∞   ∞   ∞    -
C     0*  3   1*  2   8   ∞    A-C 1
D     0*  3   1*  2*  4   9    C-D 2
B     0*  3*  1*  2*  4   9    A-B 3
E     0*  3*  1*  2*  4*  6    D-E 4
F     0*  3*  1*  2*  4*  6*   E-F 6
Prim order A C(via A-C 1) D(via C-D 2) B(via A-B 3) E(via D-E 4) F(via E-F 6) total 16

Aynı MST, farklı ekleme sırası. F’den başlasaydın sıra F, E, D, C, A, B olurdu ama kenarlar ve toplam 16 yine aynı.

İPUCU · Prim mi Kruskal mı? Seyrek grafta ve kenar listesi verildiğinde Kruskal pratiktir. Yoğun grafta (komşuluk matrisi) Prim’in O(V2)O(V^2) sürümü iyidir. Sınavda hangisi istenirse onun sırasını yaz; ikisini karıştırma.

MST tek mi?

Bütün kenar ağırlıkları farklıysa MST tektir. Eşit ağırlıklar varsa birden fazla MST olabilir, ama hepsinin toplamı aynıdır.

H grafı: P-Q 2, P-R 3, Q-R 2, Q-S 4, R-S 4, R-T 5, S-T 1.

  S-T 1 ACCEPT
  P-Q 2 ACCEPT
  Q-R 2 ACCEPT
  P-R 3 reject
  Q-S 4 ACCEPT
Kruskal total 9 edges 4

Q-S yerine R-S (o da 4) alınsaydı da {P, Q, R} ile {S, T} bağlanırdı ve toplam yine 9 olurdu. İki geçerli MST var.

Quiz provası

Quiz’de genelde 15-20 dakikada tek bir graf verilir ve üç şey istenir. Kendini zamanla dene (G grafı):

1) Kruskal'ın kabul ettiği kenarlar sırayla?
2) Prim B'den başlarsa ekleme sırası?
3) MST ağırlığı?
cevaplar:
1) A-C, C-D, A-B, D-E, E-F
2) B, A(3), C(1), D(2), E(4), F(6)
3) 16
  1. cevabın kontrolü: B’den A=3, D=5, C=7, E=10. A eklenir, C=1 olur. C eklenir, D=2, E=8. D eklenir, E=4, F=9. E eklenir, F=6. Kâğıda tabloyu çizmeden yapma; ezbere giden en sık hata, B’den başlayınca D=5’i seçmek.

Karmaşıklık özeti

AlgoritmaVeri yapısıSüre
Kruskalsıralama + union-findO(Elog⁡E)O(E \log E)
Primbinary heapO(Elog⁡V)O(E \log V)
Primdizi taramasıO(V2)O(V^2)
union-findsize + compressionişlem başına ≈O(1)\approx O(1)

Sık yapılan hatalar

Yanlış düşünceDoğrusu
Prim’de d[u] = d[v] + wPrim’de d[u] = w(v,u); toplam yol Dijkstra’dır
MST = kaynaktan en kısa yollar ağacıFarklı şeyler; MST toplam ağırlığı, Dijkstra her yolu küçültür
Kruskal her adımda bağlı bir ağaç tutarKruskal orman tutar, en sonda birleşir; tek ağaç Prim’dir
Prim’de son eklenenin komşusunu seçAğaçtaki TÜM düğümlerin dışarı kenarlarından en hafifi
Union’da a’yı doğrudan b’ye bağlaKÖKLERİ bağla: parent[find(b)] = find(a)
Eşit ağırlıkta farklı MST = yanlışToplam aynıysa geçerli
MST’de V kenarV − 1 kenar

Kendini test et

Sınavdaki gibi İngilizce sorular. Önce kâğıt kalemle çöz, sonra cevabı aç.

Soru 1kolay

Graph G (undirected): A-B 3, A-C 1, B-C 7, B-D 5, C-D 2, C-E 8, D-E 4, D-F 9, E-F 6, B-E 10. How many edges does its MST have, and what is the total weight?

Cevabı göster
5 edges, total weight 16

6 düğümlü ağaçta V-1 = 5 kenar olur. Kruskal A-C 1, C-D 2, A-B 3, D-E 4, E-F 6 alır: 1+2+3+4+6 = 16.

Soru 2orta

Run Kruskal's algorithm on G. In which order are edges accepted?

Cevabı göster
A-C 1, C-D 2, A-B 3, D-E 4, E-F 6

Kenarları ağırlığa göre sırala: A-C 1, C-D 2, A-B 3, D-E 4, B-D 5, E-F 6, B-C 7, C-E 8, D-F 9, B-E 10.
A-C, C-D, A-B, D-E kabul. B-D 5: B ve D zaten aynı kümede (A-B ve A-C-D üzerinden), red. E-F 6 kabul. 5 kenar oldu, dur.

Soru 3orta

Which edge is the first one Kruskal rejects on G, and why?

Cevabı göster
B-D 5, because B and D are already connected (B-A-C-D), so it would form a cycle

B-D geldiğinde find(B) = find(D) = A. Bu kenar B-A-C-D-B döngüsünü kapatırdı. Döngü özelliği (cycle property): bir döngünün en ağır kenarı (burada B-D 5 > 3, 1, 2) MST'de olmak zorunda değildir.

Soru 4orta

Run Prim's algorithm on G starting from A. In which order are vertices added, and through which edge?

Cevabı göster
A, C (A-C 1), D (C-D 2), B (A-B 3), E (D-E 4), F (E-F 6)

ekle  A  B  C  D  E  F
A     0* 3  1  ∞  ∞  ∞
C     0* 3  1* 2  8  ∞
D     0* 3  1* 2* 4  9
B     0* 3* 1* 2* 4  9
E     0* 3* 1* 2* 4* 6
F     0* 3* 1* 2* 4* 6*
Her adımda ağaca en ucuz bağlanan düğüm seçilir. D eklenince B=3 ile E=4 yarışır; B kazanır.

Soru 5orta

Run Prim on G starting from F. Give the order of added vertices.

Cevabı göster
F, E, D, C, A, B

F: E=6, D=9. E eklenir (6): D=4, C=8, B=10. D eklenir (4): C=2, B=5. C eklenir (2): A=1. A eklenir (1): B=3. B eklenir (3).
Kenarlar F-E 6, E-D 4, D-C 2, C-A 1, A-B 3: yine 16. Başlangıç düğümü sırayı değiştirir, ağırlıkları farklı olan grafta MST'yi değiştirmez.

Soru 6orta

Cut property: in G, consider the cut S = {A, B} versus the rest {C, D, E, F}. Which edges cross the cut, and which one must be in every MST?

Cevabı göster
A-C 1, B-C 7, B-D 5, B-E 10 cross; A-C 1 must be in the MST

Kesimi geçen kenarlar bir ucu S'de, diğeri dışarıda olanlar. Kesim özelliği (cut property): kesimi geçen en hafif kenar (benzersizse) her MST'dedir. Prim de her adımda 'ağaç' ile 'geri kalanı' arasındaki kesimin en hafif kenarını alır.

Soru 7zor

Union-find on 0..7 with union by size (on equal size, the second root goes under the first) and path compression. Perform union(0,1), union(2,3), union(4,5), union(6,7), union(0,2), union(4,6), union(0,4). Give the parent array.

Cevabı göster
[0, 0, 0, 2, 0, 4, 4, 6]

İlk dört union: 1→0, 3→2, 5→4, 7→6. union(0,2): iki kök de boy 2, 2→0. union(4,6): 6→4. union(0,4): boyutlar 4 ve 4, 4→0.

        0
      / | \
     1  2  4
        |  | \
        3  5  6
              |
              7
Bu union'larda find çağrıları zaten köklerde olduğu için sıkıştırma bir şey değiştirmedi.

Soru 8zor

Continuing from the previous state, call find(7) with path compression. What does it return, and what is the parent array afterwards?

Cevabı göster
Returns 0; parent = [0, 0, 0, 2, 0, 4, 0, 0]

Yol 7 → 6 → 4 → 0. Path compression yoldaki her düğümü doğrudan köke bağlar: parent[7] = 0, parent[6] = 0 (4 zaten 0'a bağlı). Bir sonraki find(7) tek adımda biter.

Soru 9zor

Graph H: P-Q 2, P-R 3, Q-R 2, Q-S 4, R-S 4, R-T 5, S-T 1. What is the MST weight? Is the MST unique?

Cevabı göster
Weight 9; not unique (either Q-S 4 or R-S 4 can be used)

Kruskal (eşitlikte listeleme sırası): S-T 1, P-Q 2, Q-R 2 kabul; P-R 3 red (döngü); Q-S 4 kabul. Toplam 1+2+2+4 = 9.
R-S 4 listede önce olsaydı Q-S yerine o alınırdı; yine 9. İki farklı MST, aynı ağırlık. Tüm kenar ağırlıkları farklıysa MST tektir; eşit ağırlık varsa birden fazla olabilir.

Soru 10kolay

Give the running times: (a) Kruskal with sorting and union-find, (b) Prim with a binary heap, (c) Prim with an adjacency matrix and array scan.

Cevabı göster
(a) O(E log E) = O(E log V) (b) O(E log V) (c) O(V²)

(a) Sıralama baskın: O(Elog⁡E)O(E \log E); E≤V2E \le V^2 olduğu için log⁡E≤2log⁡V\log E \le 2 \log V, yani O(Elog⁡V)O(E \log V). Union-find işlemleri neredeyse sabit. (b) Dijkstra ile aynı yapı. (c) Her adımda V eleman taranır, V adım: yoğun graf için iyi.

Soru 11orta

Write int find(int x) with path compression and boolean union(int a, int b) with union by size, using arrays parent[] and size[]. union returns false if a and b are already in the same set.

Cevabı göster
find: recursive, set parent[x] = find(parent[x]); union: attach smaller root under larger, add sizes

static int[] parent, size;
static int find(int x) {
    if (parent[x] != x)
        parent[x] = find(parent[x]);   // path compression
    return parent[x];
}
static boolean union(int a, int b) {
    int ra = find(a), rb = find(b);
    if (ra == rb) return false;        // aynı küme: döngü
    if (size[ra] < size[rb]) { int t = ra; ra = rb; rb = t; }
    parent[rb] = ra;                   // küçük, büyüğün altına
    size[ra] += size[rb];
    return true;
}
Başlangıçta parent[i] = i, size[i] = 1. İkisi birlikte işlem başına neredeyse sabit (ters Ackermann) süre verir.

Soru 12zor

Write int kruskal(int n, int[][] edges) that returns the MST weight. Each edge is {u, v, w}. Use the find/union methods from the previous question.

Cevabı göster
Sort edges by w, union endpoints, add w when union succeeds, stop at n-1 edges

static int kruskal(int n, int[][] edges) {
    parent = new int[n];
    size = new int[n];
    for (int i = 0; i < n; i++) { parent[i] = i; size[i] = 1; }
    int[][] es = edges.clone();
    Arrays.sort(es, (x, y) -> Integer.compare(x[2], y[2]));
    int total = 0, used = 0;
    for (int[] e : es) {
        if (union(e[0], e[1])) {
            total += e[2];
            if (++used == n - 1) break;
        }
    }
    return total;
}
G grafında (A..F = 0..5) 16 döner. Graf bağlı değilse used < n-1 kalır; o zaman MST yoktur, sadece yayılan orman vardır.

Doğrulama: Kruskal kabul/ret sırası ve her adımdaki parent dizisi, Prim adım tabloları (A'dan ve F'den), ikinci graftaki eşit ağırlıklı alternatif MST, union by size + path compression izi verify/SEN2212/W13.java ile çalıştırıldı (java W13.java). find/union ve kruskal metotları verify/SEN2212/WMethods11to14.java içinde test edildi.

Deftere not kartı

MST: V düğüm, V-1 kenar, döngü yok, toplam ağırlık en küçük Kesim özelliği: kesimi geçen en hafif kenar MST'de Döngü özelliği: döngünün en ağır kenarı MST'de olmak zorunda değil KRUSKAL: kenarları sırala, döngü kurmayanı al (union-find) find(u) == find(v) → RED süre O(E log E) PRIM: bir düğümden başla, ağaca EN UCUZ bağlanan düğümü ekle tablo Dijkstra gibi ama d[u] = w(v,u) (toplam yol değil!) heap O(E log V), dizi O(V²) union by size: küçük kök büyüğün altına; path compression: yolu köke bağla Ağırlıklar farklı → MST tek; eşit ağırlık → birden fazla olabilir Örnek G: 16 (A-C1, C-D2, A-B3, D-E4, E-F6)