Bölüm 12: Kümeler

Bölüm 12: Kümeler · Çalışma Soruları
Küme işlemleriUnion-Find izlemeKruskalequals ve hashCode
Klasik · çoktan seçmeli · adım adım çalıştırmalı · ucu açık sorular. Önce kendiniz çözün, sonra cevabı açın. · Sercan KÜLCÜ

Klasik Soru · Kümeler

Soru 1: Küme İşlemleri

Programın çıktısı nedir? TreeSet ile HashSet arasındaki farkı yazınız.

Set<Integer> a =
    new TreeSet<>(List.of(5, 1, 9, 3, 7));
Set<Integer> b =
    new HashSet<>(List.of(3, 4, 5, 6));
Set<Integer> k = new TreeSet<>(a);
k.retainAll(b);
Set<Integer> f = new TreeSet<>(a);
f.removeAll(b);
Set<Integer> u = new TreeSet<>(a);
u.addAll(b);
System.out.println(k + " " + f + " "
    + u.size() + " " + a.add(3));
Cevabı göster
  • retainAll = kesişim A ∩ B = [3, 5]
  • removeAll = fark A − B = [1, 7, 9]
  • addAll = birleşim = [1, 3, 4, 5, 6, 7, 9] → boyut 7
  • 3 zaten A'da: add false döner (küme tekrar tutmaz).

Çıktı: [3, 5] [1, 7, 9] 7 false

TreeSet: kırmızı-siyah ağaç, elemanlar sıralı, işlemler O(log n). HashSet: hash tablosu, sıra garantisi yok, ortalama O(1).

Klasik Soru · Kümeler

Soru 2: Union-Find İzleme

0..7 elemanlı ayrık küme yapısı ata[i] = i, rutbe[i] = 0 ile başlıyor. Rütbeye göre birleştirme: küçük rütbeli kök büyüğün altına bağlanır; eşitse kok1.ata = kok2 yapılır ve kok2'nin rütbesi 1 artar. Yol kısaltma uygulanır.
union(0,1), union(2,3), union(4,5), union(1,3), union(6,7), union(5,7), union(3,7)
(a) Son ata ve rutbe dizileri? (b) Ardından find(0) çağrılınca ata nasıl değişir?

Cevabı göster
  • union(0,1): 0 → 1, r[1]=1 · union(2,3): 2 → 3, r[3]=1 · union(4,5): 4 → 5, r[5]=1
  • union(1,3): kökler 1 ve 3, rütbe eşit → 1 → 3, r[3]=2
  • union(6,7): 6 → 7, r[7]=1 · union(5,7): eşit → 5 → 7, r[7]=2
  • union(3,7): kökler 3 ve 7, rütbe eşit (2) → 3 → 7, r[7]=3
i01234567
ata13375777
rutbe01020103
find(0) sonrası ata77375777

(b) find(0) yolu 0 → 1 → 3 → 7. Yol kısaltma ile yol üzerindeki 0 ve 1 doğrudan köke (7) bağlanır.

Rütbe + yol kısaltma ile işlem başına amortize ≈ O(α(n)), pratikte sabit.

Klasik Soru · Kümeler

Soru 3: Kruskal ile Minimum Kapsayan Ağaç

Ağırlıklı yönsüz çizgenin minimum kapsayan ağacını (MST) Kruskal algoritmasıyla bulunuz. Kenarları hangi sırayla incelediğinizi, hangilerinin neden reddedildiğini ve toplam ağırlığı yazınız. Union-Find bu algoritmada ne işe yarar?

635274891ABCDEF
Cevabı göster
KenarAğırlıkKarar
E–F1eklendi
B–D2eklendi
A–C3eklendi
C–E4eklendi
B–C5eklendi
A–B6döngü → reddedildi

MST kenarları: E–F (1), B–D (2), A–C (3), C–E (4), B–C (5). V − 1 = 5 kenar seçilince durulur.

Toplam ağırlık: 15. A–B (6) reddedilir çünkü A ve B zaten C üzerinden bağlı.

Union-Find: kenarın iki ucu için find(u) == find(v) ise kenar döngü oluşturur; değilse union(u, v). Toplam O(E log E).

Klasik Soru · Kümeler

Soru 4: equals ve hashCode

Ogrenci sınıfı yalnızca equals metodunu (numaraya göre) geçersiz kılıyor, hashCode'u kılmıyor. Çıktı nedir? Neden? Nasıl düzeltilir?

class Ogrenci {
    int no; String ad;
    Ogrenci(int no, String ad) {
        this.no = no; this.ad = ad;
    }
    @Override
    public boolean equals(Object o) {
        return o instanceof Ogrenci x
               && x.no == no;
    }
}
Set<Ogrenci> s = new HashSet<>();
s.add(new Ogrenci(7, "Ali"));
s.add(new Ogrenci(7, "Ali"));
System.out.println(s.size() + " "
    + s.contains(new Ogrenci(7, "Ali")));
Cevabı göster

Çıktı büyük olasılıkla: 2 false

HashSet önce hashCode ile kovayı bulur, sonra yalnızca o kovada equals ile karşılaştırır. Varsayılan hashCode nesne kimliğine dayanır; eşit iki öğrenci farklı kovalara düşer, equals hiç çağrılmaz.

Sözleşme: a.equals(b) ise a.hashCode() == b.hashCode() olmalıdır.

@Override
public int hashCode() {
    // equals ile aynı alan kullanılır
    return Integer.hashCode(no);
}

Düzeltme sonrası çıktı: 1 true. TreeSet kullanılsaydı compareTo/Comparator tutarlı olmalıydı.

Çoktan Seçmeli · Kümeler

Test 1

A = {1, 2, 3, 4}, B = {3, 4, 5} için simetrik fark A Δ B nedir?

Yalnızca birinde olanlar: (A − B) ∪ (B − A) = {1, 2} ∪ {5}.

HashSet'e sırasıyla "a", "b", "a", "c", "b" eklenince size() kaçtır?

Küme tekrar tutmaz; tekrar eden add çağrıları false döndürür. {a, b, c}.

Çoktan Seçmeli · Kümeler

Test 2

Yol kısaltma ve rütbeye göre birleştirme birlikte kullanıldığında Union-Find işlemlerinin amortize maliyeti nedir?

α ters Ackermann fonksiyonudur; evrendeki atom sayısı kadar n için bile ≤ 4.

Kruskal algoritması bir kenarı neden reddeder?

find(u) == find(v) ise u ve v zaten bağlıdır; kenarı eklemek döngü oluşturur.

Adım Adım Çalıştırma · Kümeler

Union-Find ve Yol Kısaltma

Basit birleştirme (rütbesiz) ve yol kısaltmalı find ile işlemleri izleyin.

ata001122334455

Önce tahmin edin: find(0) sonrası ata dizisi ne olur?

ata001122334455

Her eleman kendi kümesinin köküdür.

ata101122334455

union(0,1): find(0) = 0, find(1) = 1 → ata[0] = 1.

ata102122334455

union(1,2): find(1) = 1, find(2) = 2 → ata[1] = 2.

ata102122434455

union(3,4): find(3) = 3, find(4) = 4 → ata[3] = 4.

ata102142434455

union(2,4): find(2) = 2, find(4) = 4 → ata[2] = 4.

ata102142434455

find(0): 0 → 1 → 2 → 4 zinciri boyunca özyinelemeli çağrılar.

ata102142434455

ata[4] = 4: kök bulundu, 4 döner.

ata104142434455

Dönüşte yol kısaltma: ata[2] = 4 (zaten), ata[1] = 4.

ata404142434455

ata[0] = 4. Artık 0 ve 1 doğrudan köke bağlı: sonraki find'lar tek adım.

int[] ata = {0, 1, 2, 3, 4, 5};
int find(int x) {
    if (ata[x] != x) ata[x] = find(ata[x]);
    return ata[x];
}
void union(int a, int b) {
    ata[find(a)] = find(b);
}
// union(0,1); union(1,2);
// union(3,4); union(2,4);
// find(0);

Ucu Açık Soru · Kümeler

Arkadaş Grupları

  1. Bir sosyal ağda "kaç ayrı arkadaş grubu (bağlı bileşen) var?" ve "A ile B aynı grupta mı?" soruları soruluyor. Arkadaşlıklar sürekli ekleniyor, hiç silinmiyor. Union-Find mı, her sorguda BFS/DFS mi? Karşılaştırın.
  2. Arkadaşlıklar silinebilseydi Union-Find neden yetersiz kalırdı? Ne yapılabilir?
Örnek cevap ve değerlendirme ölçütleri

1. Union-Find: her yeni arkadaşlık union(a, b), sorgu find(a) == find(b), işlem başına amortize ≈ O(1). Grup sayısı bir sayaçla tutulur: başlangıçta n, gerçekleşen her birleşmede 1 azalır. BFS/DFS her sorguda O(V + E) sürer; sık sorgu ve sürekli eklemede çok yavaştır. Çizge değişmiyor ve tek seferlik analiz yapılıyorsa BFS/DFS de yeterlidir.

2. Union-Find kümeleri yalnızca birleştirir, bölemez. Bir kenar silinince grup ikiye ayrılabilir ama yapı bunu ifade edemez. Çözümler: silmeden sonra etkilenen bileşende BFS/DFS ile yeniden hesaplama; silmeler biliniyorsa işlemleri ters sırada çalıştırmak (silmeyi eklemeye çevirmek); ya da dinamik bağlantılılık için daha gelişmiş yapılar.

Değerlendirme: iki yaklaşımın karmaşıklık karşılaştırması · bileşen sayacının tutulması · Union-Find'ın bölme yapamadığının fark edilmesi · makul bir alternatif.

Son

Bölüm 12: Kümeler: Çalışma Soruları
Konu anlatımı: Kümeler sunumu
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.