Bölüm 12: Rastgele Algoritmalar
Giriş
Öğrenme Çıktıları
Rastgele algoritmanın tanımını, beklenen çalışma süresini ve Las Vegas / Monte Carlo ayrımını açıklamak.
Fisher–Yates karıştırmasını yazmak, saf karıştırmanın neden yanlı olduğunu göstermek; BogoSort'un beklenen Θ(n · n!) süresini hesaplamak.
Rastgele pivotlu parçalamayı adım adım izlemek; beklenen O(n log n) ve en kötü O(n²) süreyi gerekçelendirmek.
π tahmini, Miller–Rabin asallık testi ve Karger min-kesim algoritmasında hata olasılığını hesaplamak ve tekrarla küçültmek.
Giriş
Şanslı Algoritmalar
- Bazen problem çözmede şans oyunlarına benzer teknikler kullanılır.
- Algoritma, karar verme sürecinde rastgelelikten (şans) yararlanır: yazı-tura atar, zar atar, rastgele bir öğe seçer.
- Örnek oyun: iki zar atılır; toplam 7 ya da 11 ise oyuncu kazanır.
Giriş
Rastgele Algoritmalar
- Rastgele algoritma (randomized algorithm): girdiye ek olarak rastgele sayılar kullanarak çalışır.
- Aynı girdiyle iki çalıştırma farklı adımlar izleyebilir: çalışma süresi (ve bazen çıktı) her çalıştırmada değişebilir.
- Süre artık bir rastgele değişkendir: beklenen süre E[T(n)] incelenir. Beklenen değer algoritmanın kendi yazı-turaları üzerinden alınır, girdi üzerinden değil.
Giriş
Neden Rastgelelik?
Deterministik QuickSort sıralı dizide O(n²) olur. Rastgele pivotta hiçbir girdi sürekli kötü değildir: kötü durum yalnızca şanssız yazı-turalarla oluşur.
Rastgele algoritma çoğu zaman en iyi deterministik algoritmadan çok daha kısa ve anlaşılırdır (Karger min-kesim, rastgele QuickSelect).
Miller–Rabin, yüzlerce basamaklı sayıların asallığını milisaniyeler içinde, çok küçük bir hata olasılığıyla belirler.
Monte Carlo benzetimleri, rastgele örneklem ve dağıtık sistemlerde lider seçimi gibi işler rastgelelik olmadan zordur.
Bedel: süre ya da doğruluk artık olasılıksal bir garantidir; iyi bir rastgele sayı üreteci gerekir.
Giriş
Olasılık Hatırlatması
| Kavram | Tanım / kural | Örnek |
|---|---|---|
| Beklenen değer | E[X] = Σ x · P(X = x) | bir zarın beklenen değeri 3,5 |
| Doğrusallık | E[X + Y] = E[X] + E[Y] (bağımsızlık gerekmez) | iki zarın toplamı: 7 |
| Gösterge değişkeni | XA = 1 (A olursa), 0 → E[XA] = P(A) | QuickSort'ta "i ile j karşılaştırıldı mı?" |
| Geometrik dağılım | başarı olasılığı p olan denemeler: ilk başarıya kadar beklenen deneme 1/p | BogoSort: p = 1/n! → n! karıştırma |
| Bağımsız tekrar | her biri p ile başarısız k bağımsız deneme: hepsi başarısız pk | Miller–Rabin: (1/4)k |
| Markov eşitsizliği | X ≥ 0 ise P(X ≥ c · E[X]) ≤ 1/c | Las Vegas → Monte Carlo |
Algoritma Türleri
Las Vegas ve Monte Carlo
| Las Vegas | Monte Carlo | |
|---|---|---|
| Doğruluk | Her zaman doğru sonuç | Küçük bir olasılıkla yanlış sonuç |
| Süre | Rastgele; beklenen süre analiz edilir | Sınırlı (deterministik üst sınır) |
| Rastgele olan | ne kadar süreceği | sonucun doğru olup olmadığı |
| Örnekler | Rastgele QuickSort, QuickSelect, BogoSort, Fisher–Yates | Miller–Rabin, Karger min-kesim, π tahmini |
Miller–Rabin "bileşik" derse kesin doğrudur; yalnızca "asal" yanıtı yanlış olabilir.
π tahmini gibi sayısal benzetimler her iki yönde de sapabilir; hata örnek sayısıyla küçülür.
Algoritma Türleri
Hata Olasılığını Küçültme
Tek turda yanılma olasılığı en çok q ise, k bağımsız tur sonra yanılma ≤ qk.
- Miller–Rabin: q ≤ 1/4 → k = 20 turda ≤ 4−20 ≈ 9 · 10−13.
- Karger: başarı ≥ 2/(n(n−1)); n(n−1)/2 · ln n tekrarla başarısızlık ≤ 1/n.
- Las Vegas → Monte Carlo: algoritmayı 2 · E[T] adım sonra durdur. Markov: P(T ≥ 2 E[T]) ≤ 1/2 → en çok 1/2 olasılıkla "yanıt yok".
- Monte Carlo → Las Vegas: yanıt hızlıca doğrulanabiliyorsa (ör. bulunan çarpanlar çarpılır), doğru çıkana kadar tekrarla. Beklenen tekrar = 1/p.
Miller–Rabin hata sınırı 4−k (logaritmik ölçek): her tur sınırı 4'e böler. 10−6'nın altı için k = 10 tur yeter.
Karıştırma
Örnek: Karıştırma
- Sıralı bir listenin öğelerini karıştırmak (shuffle) için rastgelelik kullanılır: kart destesi, rastgele test verisi, şarkı listesi.
- Doğruluk: her öğenin her konumda eşit olasılıkla bulunması; daha güçlüsü, n! permütasyonun her birinin olasılığı 1/n! olmalı.
- Çalışma zamanı: Fisher–Yates her çalıştırmada tam n − 1 takas yapar: Θ(n). Değişen, sürenin değil sonucun kendisidir.
- Java'da hazır:
Collections.shuffle(liste)(Fisher–Yates).
| n | n! permütasyon |
|---|---|
| 3 | 6 |
| 4 | 24 |
| 10 | 3 628 800 |
| 52 | ≈ 8,07 · 1067 |
Karıştırma · Kodu adım adım çalıştır
Fisher–Yates (Knuth) Karıştırması
Başlangıç: a = [1, 2, 3, 4, 5]. Sondan başlayarak her konuma, henüz yerleşmemiş öğelerden biri rastgele seçilir.
i = 4: a[0..4] arasındaki 5 öğeden biri a[4] konumuna gelecek.
zar.nextInt(5) → j = 1 (olasılık 1/5).
a[4] ↔ a[1] takas → [1, 5, 3, 4, 2]. a[4] = 2 artık kesinleşti (yeşil).
i = 3: a[0..3] arasındaki 4 öğeden biri a[3] konumuna gelecek.
zar.nextInt(4) → j = 3 (j = i: öğe yerinde kalır).
Kendisiyle takas: dizi değişmez; a[3] = 4 kesinleşti.
i = 2: a[0..2] arasındaki 3 öğeden biri a[2] konumuna gelecek.
zar.nextInt(3) → j = 0 (olasılık 1/3).
a[2] ↔ a[0] takas → [3, 5, 1, 4, 2]. a[2] = 1 artık kesinleşti (yeşil).
i = 1: a[0..1] arasındaki 2 öğeden biri a[1] konumuna gelecek.
zar.nextInt(2) → j = 1 (j = i: öğe yerinde kalır).
Kendisiyle takas: dizi değişmez; a[1] = 5 kesinleşti.
Döngü bitti: [3, 5, 1, 4, 2]. Toplam olası çekiliş sayısı 5 · 4 · 3 · 2 = 120 = 5!: her permütasyon tam bir kez → düzgün dağılım.
static void karistir(int[] a) { for (int i = a.length - 1; i > 0; i--) { int j = zar.nextInt(i + 1); // 0 ≤ j ≤ i int t = a[i]; a[i] = a[j]; a[j] = t; } }
Karıştırma
Saf Karıştırma Yanlıdır
// YANLI: her i için 0..n-1 arasından seç for (int i = 0; i < n; i++) { int j = zar.nextInt(n); takas(a, i, j); }
- n çekilişin her biri n değer alır → nn eşit olasılıklı yol.
- n = 3: 33 = 27 yol, 3! = 6 permütasyon. 27, 6'ya bölünmez → permütasyonlar eşit olasılıklı olamaz.
- Sık görülen bu kalıbın doğrusu Fisher–Yates'tir:
nextInt(i + 1).
| sonuç | yol | olasılık | olması gereken |
|---|---|---|---|
123 | 4/27 | 0,148 | 1/6 ≈ 0,167 |
132 | 5/27 | 0,185 | 1/6 ≈ 0,167 |
213 | 5/27 | 0,185 | 1/6 ≈ 0,167 |
231 | 5/27 | 0,185 | 1/6 ≈ 0,167 |
312 | 4/27 | 0,148 | 1/6 ≈ 0,167 |
321 | 4/27 | 0,148 | 1/6 ≈ 0,167 |
[1, 2, 3] dizisinin 27 çekiliş dizisi tek tek sayıldı (Fisher–Yates'te 3 · 2 = 6 yol, her permütasyon 1 kez).
BogoSort
BogoSort
- Sıralama algoritmaları arasında en kötü performansa sahip olanlardan biridir ("aptal sıralama", permutation sort).
- Temel mantık: liste sıralı olana kadar rastgele karıştır.
- Eğlenceli ve öğretici bir Las Vegas algoritmasıdır; gerçek dünyada kullanılmaz.
- Liste sıralı mı? Evet → işlemi tamamla.
- Hayır → listeyi rastgele karıştır, adım 1'e dön.
static void bogoSirala(int[] a) { while (!siraliMi(a)) karistir(a); // Fisher–Yates } static boolean siraliMi(int[] a) { for (int i = 0; i + 1 < a.length; i++) if (a[i] > a[i + 1]) return false; return true; }
BogoSort
BogoSort Örneği: [5, 2, 8, 4]
[5, 2, 8, 4] listesi; her karıştırma Fisher–Yates ile (tohumlu bir çalıştırma). Kırmızı: ilk ters sıralı komşu çift.
Başlangıç [5, 2, 8, 4]: a[0] = 5 > a[1] = 2 → sıralı değil, karıştırmaya başla.
Karıştırma 1: [5, 4, 2, 8] → a[0] = 5 > a[1] = 4, sıralı değil.
Karıştırma 2: [8, 4, 5, 2] → a[0] = 8 > a[1] = 4, sıralı değil.
Karıştırma 3: [4, 2, 8, 5] → a[0] = 4 > a[1] = 2, sıralı değil.
Karıştırma 4: [2, 8, 4, 5] → a[1] = 8 > a[2] = 4, sıralı değil.
Karıştırma 5: [5, 8, 2, 4] → a[1] = 8 > a[2] = 2, sıralı değil.
Karıştırma 6: [8, 4, 2, 5] → a[0] = 8 > a[1] = 4, sıralı değil.
Karıştırma 7: [2, 8, 5, 4] → a[1] = 8 > a[2] = 5, sıralı değil.
Karıştırma 8: [2, 4, 5, 8] → sıralı! Algoritma durur. Bu çalıştırmada 8 karıştırma gerekti; beklenen değer 4! = 24.
BogoSort
BogoSort Analizi
- n farklı öğe: rastgele bir karıştırmanın sıralı çıkma olasılığı p = 1/n!.
- Denemeler bağımsız → geometrik dağılım: beklenen karıştırma sayısı 1/p = n!.
- Her tur: karıştırma O(n) + kontrol O(n) → beklenen süre Θ(n · n!). Bu, O((n + 1)!) ile aynı büyüklüktedir, çünkü (n + 1)! = (n + 1) · n!.
- En iyi durum: dizi zaten sıralı → tek kontrol, O(n).
- En kötü durum: sınırsız. Şanssız karıştırmalar sonsuza dek sürebilir (olasılığı 0'a gider). O((n + 1)!) yalnızca beklenen süre için bir sınırdır, en kötü durum için değil.
| n | beklenen karıştırma n! | süre (10⁹ karıştırma/s) |
|---|---|---|
| 5 | 120 | 0,12 µs |
| 10 | 3 628 800 | 3,6 ms |
| 12 | 479 001 600 | 0,48 s |
| 13 | 6 227 020 800 | 6,2 s |
| 15 | 1 307 674 368 000 | ≈ 22 dakika |
| 20 | 2 432 902 008 176 640 000 | ≈ 77 yıl |
Rastgele QuickSort
Pivot Seçimi ve Etkisi
| Pivot stratejisi | Kötü girdi | Beklenen / tipik | En kötü |
|---|---|---|---|
| İlk ya da son öğe | sıralı / ters sıralı dizi (çok yaygın!) | O(n log n)* | O(n²) |
| Ortanca-üç (median-of-3) | özel hazırlanmış "killer" diziler | O(n log n)* | O(n²) |
| Rastgele öğe | yok: kötülük yalnızca şanssızlıktan | O(n log n), her girdi için | O(n²) |
| Gerçek ortanca (BFPRT) | yok | O(n log n) | O(n log n) |
- * Deterministik stratejilerde O(n log n) yalnızca girdi rastgele sıralıysa geçerlidir (ortalama durum). Rastgele pivotta ise beklenti algoritmanın kendi seçimleri üzerindendir (beklenen süre).
- İyi pivot seçimi beklenen süreyi iyileştirir, en kötü durumu ortadan kaldırmaz: rastgele pivotta da O(n²) mümkündür, ama olasılığı çok küçüktür.
- BFPRT'nin sabitleri büyüktür; uygulamada rastgele ya da ortanca-üç pivot tercih edilir.
Rastgele QuickSort
Rastgele Pivotlu QuickSort Çalıştırması
[6, 5, 3, 1, 8, 7, 2, 4]; pivotlar rastgele seçildi: 3, 1, 4, 6, 8. Siyah: pivot · kırmızı çerçeve: i ve j işaretçileri · yeşil: kesinleşmiş · soluk: etkin alt dizinin dışı.
Alt dizi a[0..7] = [6, 5, 3, 1, 8, 7, 2, 4]: pivot rastgele seçildi → 3 (indis 2, siyah kutu).
i soldan ilerler, 3'ten küçükleri atlar ve a[0] = 6'da durur; j sağdan ilerler, 3'ten büyükleri atlar ve a[6] = 2'de durur. i < j → takas edilecek.
a[0] ↔ a[6] takas → [2, 5, 3, 1, 8, 7, 6, 4].
i soldan ilerler, 3'ten küçükleri atlar ve a[1] = 5'te durur; j sağdan ilerler, 3'ten büyükleri atlar ve a[3] = 1'de durur. i < j → takas edilecek.
a[1] ↔ a[3] takas → [2, 1, 3, 5, 8, 7, 6, 4].
İşaretçiler karşılaştı (i ≥ j): pivot 3 kalıcı yerinde (indis 2). Solunda yalnızca küçükler, sağında yalnızca büyükler var.
Alt dizi a[0..1] = [2, 1]: pivot rastgele seçildi → 1 (indis 1, siyah kutu).
i soldan ilerler, 1'den küçükleri atlar ve a[0] = 2'de durur; j sağdan ilerler, 1'den büyükleri atlar ve a[1] = 1'de durur. i < j → takas edilecek.
a[0] ↔ a[1] takas → [1, 2, 3, 5, 8, 7, 6, 4]. Pivotun kendisi de yer değiştirebilir; konumu izlenir.
İşaretçiler karşılaştı (i ≥ j): pivot 1 kalıcı yerinde (indis 0). Solunda yalnızca küçükler, sağında yalnızca büyükler var.
Tek öğeli alt dizi a[1] = 2 zaten sıralı: kesinleşti.
Alt dizi a[3..7] = [5, 8, 7, 6, 4]: pivot rastgele seçildi → 4 (indis 7, siyah kutu).
i soldan ilerler, 4'ten küçükleri atlar ve a[3] = 5'te durur; j sağdan ilerler, 4'ten büyükleri atlar ve a[7] = 4'te durur. i < j → takas edilecek.
a[3] ↔ a[7] takas → [1, 2, 3, 4, 8, 7, 6, 5]. Pivotun kendisi de yer değiştirebilir; konumu izlenir.
İşaretçiler karşılaştı (i ≥ j): pivot 4 kalıcı yerinde (indis 3). Solunda yalnızca küçükler, sağında yalnızca büyükler var.
Alt dizi a[4..7] = [8, 7, 6, 5]: pivot rastgele seçildi → 6 (indis 6, siyah kutu).
i soldan ilerler, 6'dan küçükleri atlar ve a[4] = 8'de durur; j sağdan ilerler, 6'dan büyükleri atlar ve a[7] = 5'te durur. i < j → takas edilecek.
a[4] ↔ a[7] takas → [1, 2, 3, 4, 5, 7, 6, 8].
i soldan ilerler, 6'dan küçükleri atlar ve a[5] = 7'de durur; j sağdan ilerler, 6'dan büyükleri atlar ve a[6] = 6'da durur. i < j → takas edilecek.
a[5] ↔ a[6] takas → [1, 2, 3, 4, 5, 6, 7, 8]. Pivotun kendisi de yer değiştirebilir; konumu izlenir.
İşaretçiler karşılaştı (i ≥ j): pivot 6 kalıcı yerinde (indis 5). Solunda yalnızca küçükler, sağında yalnızca büyükler var.
Tek öğeli alt dizi a[4] = 5 zaten sıralı: kesinleşti.
Alt dizi a[6..7] = [7, 8]: pivot rastgele seçildi → 8 (indis 7, siyah kutu).
Pivot 8: i, 7'yi atlayıp 8'de durur; j zaten 8'de. i ≥ j → takas yok, 8 kalıcı yerinde (indis 7).
Tek öğeli alt dizi a[6] = 7 zaten sıralı: kesinleşti. Dizi sıralandı: [1, 2, 3, 4, 5, 6, 7, 8].
Rastgele QuickSort
Rastgele QuickSort: Kod
static Random zar = new Random(); static void hizliSirala(int[] a, int alt, int ust) { if (alt < ust) { int p = bol(a, alt, ust); // rastgele hizliSirala(a, alt, p - 1); hizliSirala(a, p + 1, ust); } } static int bol(int[] a, int alt, int ust) { int r = alt + zar.nextInt(ust - alt + 1); takas(a, r, ust); // pivot sona int pivot = a[ust], k = alt; for (int i = alt; i < ust; i++) if (a[i] <= pivot) takas(a, i, k++); // küçükleri sola takas(a, k, ust); // pivot yerine return k; }
- Pivot, alt dizinin öğeleri arasından düzgün rastgele seçilir. Sonuç her zaman doğrudur (Las Vegas); yalnızca süre pivot seçimlerine bağlıdır.
bolrastgele indisi sona taşır ve Lomuto parçalaması uygular: [6, 5, 3, 1, 8, 7, 2, 4] için r = 2 (pivot 3) → [1, 2, 3, 6, 8, 7, 5, 4], dönüş 2.- Ek bellek: özyineleme yığını; beklenen derinlik O(log n). Küçük parçaya önce inilip büyük parça döngüye çevrilirse en kötü durumda da O(log n).
- Tekrarlı anahtarlar çoksa üç yollu parçalama (<, =, >) kullanılır.
Rastgele QuickSort
QuickSort Analizi
| Durum | Özyineleme bağıntısı | Süre |
|---|---|---|
| En iyi | T(n) = 2T(n/2) + Θ(n) | Θ(n log n) |
| Beklenen (rastgele pivot) | T(n) = (1/n) Σq [T(q) + T(n−1−q)] + Θ(n) | Θ(n log n) |
| En kötü | T(n) = T(n−1) + Θ(n) | Θ(n²) |
Rastgele pivotta en kötü durumun olasılığı: her adımda en küçük ya da en büyük seçilmeli → 2n−1/n! (n = 20 için ≈ 2 · 10−13).
Rastgele QuickSort
Beklenen Karşılaştırma
- Öğeleri sıralı hâlleriyle adlandır: z1 < z2 < … < zn. Gösterge Xij = 1 ⇔ zi ile zj karşılaştırılır.
- İki öğe yalnızca biri pivotken karşılaştırılır. {zi, …, zj} kümesinden ilk seçilen pivot arada bir öğe olursa zi ile zj ayrı parçalara düşer ve hiç karşılaşmaz.
- Bu kümeden ilk pivot düzgün rastgeledir → P(Xij = 1) = 2 / (j − i + 1).
- Doğrusallık: E[X] = Σi<j 2/(j − i + 1) < 2n Hn ≈ 1,39 n log₂ n.
- Kesin değer: E[X] = 2(n + 1)Hn − 4n.
| n | rastgele pivot (beklenen) | sıralı girdi, ilk öğe pivot |
|---|---|---|
| 10 | 24,4 | 45 |
| 100 | 648 | 4 950 |
| 1 000 | 10 986 | 499 500 |
| 106 | 2,48 · 107 | 5,0 · 1011 |
Rastgele QuickSort
Rastgele Seçme (QuickSelect)
static int sec(int[] a, int alt, int ust, int s) { if (alt == ust) return a[alt]; int p = bol(a, alt, ust); if (s == p) return a[p]; if (s < p) return sec(a, alt, p - 1, s); return sec(a, p + 1, ust, s); }
- Amaç: dizinin s. en küçük öğesini (ör. ortanca) sıralamadan bulmak.
- Aynı rastgele parçalama kullanılır, ama yalnızca tek tarafa inilir.
- Beklenen süre O(n) (ortanca için ≈ 3,39 n karşılaştırma); en kötü O(n²).
- Örnek: [6, 5, 3, 1, 8, 7, 2, 4] için s = 2 (0 tabanlı). Pivot 3 ile parçalama p = 2 verir → ilk denemede yanıt 3.
Rastgele QuickSort · Kodu adım adım çalıştır
QuickSelect: Kodu Adım Adım İzle
Dizi [6, 5, 3, 1, 8, 7, 2, 4]; aranan s = 5 (6. en küçük). İlk çağrı tüm diziyi kapsar: alt = 0, ust = 7.
bol rastgele pivot 3 seçti; parçalama sonrası pivot kalıcı yeri p = 2: solu ≤ 3, sağı > 3.
s = 5 > p = 2 → aranan öğe sağda: yalnızca [3, 7] aralığına inilir; sol taraf bir daha incelenmez.
Yeni çağrı sec(a, 3, 7, 5): aralıkta 5 öğe var, alt ≠ ust.
bol rastgele pivot 7 seçti; parçalama sonrası pivot kalıcı yeri p = 6: solu ≤ 7, sağı > 7.
s = 5 < p = 6 → aranan öğe solda: yalnızca [3, 5] aralığına inilir.
Yeni çağrı sec(a, 3, 5, 5): aralıkta 3 öğe var, alt ≠ ust.
bol rastgele pivot 5 seçti; parçalama sonrası pivot kalıcı yeri p = 4: solu ≤ 5, sağı > 5.
s = 5 > p = 4 → aranan öğe sağda: yalnızca [5, 5] aralığına inilir; sol taraf bir daha incelenmez.
Yeni çağrı sec(a, 5, 5, 5): aralıkta 1 öğe var, alt ≠ ust.
alt = ust = 5: tek öğe kaldı → return a[5] = 6.
sec(a, 0, 7, 5) = 6: sıralı dizide 5. konum (0 tabanlı). Dizinin tamamı sıralanmadı; yalnızca gereken parçalar bölündü.
static int sec(int[] a, int alt, int ust, int s) { if (alt == ust) return a[alt]; int p = bol(a, alt, ust); if (s == p) return a[p]; if (s < p) return sec(a, alt, p - 1, s); return sec(a, p + 1, ust, s); }
Monte Carlo Algoritmaları
Monte Carlo ile π
- Birim kareye düzgün rastgele noktalar at. Çeyrek dairenin alanı π/4, karenin alanı 1 → P(içeride) = π/4, yani π ≈ 4 · iç / n.
- Hata ≈ 1/√n ile azalır: bir basamak daha doğruluk için 100 kat nokta gerekir.
static double piTahmin(int n) { int ic = 0; for (int t = 0; t < n; t++) { double x = zar.nextDouble(), y = zar.nextDouble(); if (x * x + y * y <= 1) ic++; } return 4.0 * ic / n; }
300 nokta: 239 içeride → π ≈ 4 · 239/300 = 3,187.
Monte Carlo Algoritmaları · Kodu adım adım çalıştır
Monte Carlo π: Kodu Adım Adım İzle
n = 8 nokta atılacak; ic çeyrek dairenin içine düşenleri sayar. (Tohumlu bir Random ile tekrarlanabilir çalıştırma.)
t = 0: (0,62; 0,19), x² + y² = 0,42 ≤ 1 → içeride. ic = 1.
t = 1: (0,93; 0,09), x² + y² = 0,88 ≤ 1 → içeride. ic = 2.
t = 2: (0,58; 0,49), x² + y² = 0,58 ≤ 1 → içeride. ic = 3.
t = 3: (0,00; 0,49), x² + y² = 0,24 ≤ 1 → içeride. ic = 4.
t = 4: (0,30; 0,71), x² + y² = 0,59 ≤ 1 → içeride. ic = 5.
t = 5: (0,78; 0,72), x² + y² = 1,13 > 1 → dışarıda. ic = 5.
t = 6: (0,35; 0,98), x² + y² = 1,08 > 1 → dışarıda. ic = 5.
t = 7: (0,50; 0,36), x² + y² = 0,38 ≤ 1 → içeride. ic = 6.
4.0 * 6 / 8 = 3,0. 8 noktayla hata büyüktür (≈ 1,64/√8 ≈ 0,58); n büyüdükçe tahmin π'ye yaklaşır.
static double piTahmin(int n) { int ic = 0; for (int t = 0; t < n; t++) { double x = zar.nextDouble(), y = zar.nextDouble(); if (x * x + y * y <= 1) ic++; } return 4.0 * ic / n; }
Monte Carlo Algoritmaları
Deneyin: Monte Carlo π
| nokta sayısı n | 0 |
| içeride | 0 |
| π tahmini | — |
| hata |π̂ − π| | — |
| beklenen hata ≈ 1,64/√n | — |
Yeşil: çeyrek dairenin içinde · kırmızı: dışında. Çizimde ilk 3000 nokta gösterilir, sayım tüm noktalarla sürer. 1,64 = 4 · √(p(1 − p)), p = π/4.
Monte Carlo Algoritmaları
Miller–Rabin Asallık Testi
- Fermat'nın küçük teoremi: n asal ve 1 < a < n ise an−1 ≡ 1 (mod n). Bu eşitlik bozulursa n kesin bileşiktir; ama bazı bileşikler (Carmichael sayıları) her taban için eşitliği sağlar.
- Karekök özelliği: n asal ise x² ≡ 1 (mod n) yalnızca x ≡ ±1 için sağlanır.
- n − 1 = 2s · d (d tek) yazılır; rastgele a için ad, a2d, …, a2s−1d (mod n) dizisine bakılır.
- Dizi 1 ile başlamıyor ve n − 1 hiç görünmüyorsa a, n'nin bileşik olduğunun tanığıdır (witness). Aksi hâlde n bu turu "geçer".
- Bileşik n için tabanların en çok 1/4'ü yalancıdır → k bağımsız turda hata ≤ 4−k. Her tur O(log n) modüler çarpma: toplam O(k log³ n) bit işlemi.
Monte Carlo Algoritmaları
Miller–Rabin: Kod
static boolean asalMi(long n, int k) { if (n < 4) return n == 2 || n == 3; if (n % 2 == 0) return false; long d = n - 1; int s = 0; // n-1 = 2^s·d while (d % 2 == 0) { d /= 2; s++; } for (int tur = 0; tur < k; tur++) { long a = 2 + zar.nextLong(n - 3); // [2, n-2] long x = usMod(a, d, n); // a^d mod n if (x == 1 || x == n - 1) continue; boolean tanik = true; for (int r = 1; r < s && tanik; r++) { x = x * x % n; if (x == n - 1) tanik = false; } if (tanik) return false; // kesin bileşik } return true; // muhtemelen asal }
usMod: hızlı modüler üs alma (kare al-çarp), O(log d) çarpma.- Taban a, [2, n − 2] aralığından düzgün seçilir.
longilex * xyalnızca n < 3 · 109 için taşmaz; daha büyük n içinBigInteger.modPowya daisProbablePrime.
Monte Carlo Algoritmaları · Kodu adım adım çalıştır
Miller–Rabin: Kodu Adım Adım İzle (n = 561)
n = 561 = 3 · 11 · 17 bir Carmichael sayısı: Fermat testini her tabanda geçer. n ≥ 4 ve tek → testler atlanmaz.
d = n − 1 = 560, s = 0. Şimdi 560 içindeki 2 çarpanları ayrılacak.
d çift → d /= 2, s++: d = 280, s = 1.
d çift → d /= 2, s++: d = 140, s = 2.
d çift → d /= 2, s++: d = 70, s = 3.
d çift → d /= 2, s++: d = 35, s = 4. d tek: 560 = 2⁴ · 35.
Tur 0: rastgele taban çekildi, a = 2.
x = 2³⁵ mod 561 = 263 (hızlı üs alma ile).
x = 263 ne 1 ne de n − 1 = 560 → tur bitmedi; tanik = true ile kareler denetlenecek.
r = 1: x = 263² mod 561 = 166. 560 değil.
r = 2: x = 166² mod 561 = 67. 560 değil.
r = 3: x = 67² mod 561 = 1. 560 değil. 1'e n − 1 görmeden ulaşıldı.
Dizi 560'a hiç ulaşmadı: tanik true kaldı → return false. 561 kesin bileşik; 67, 1'in ±1 dışında bir karekökü.
static boolean asalMi(long n, int k) { if (n < 4) return n == 2 || n == 3; if (n % 2 == 0) return false; long d = n - 1; int s = 0; // n-1 = 2^s·d while (d % 2 == 0) { d /= 2; s++; } for (int tur = 0; tur < k; tur++) { long a = 2 + zar.nextLong(n - 3); // [2, n-2] long x = usMod(a, d, n); // a^d mod n if (x == 1 || x == n - 1) continue; boolean tanik = true; for (int r = 1; r < s && tanik; r++) { x = x * x % n; if (x == n - 1) tanik = false; } if (tanik) return false; // kesin bileşik } return true; // muhtemelen asal }
Monte Carlo Algoritmaları · Kodu adım adım çalıştır
usMod: 2³⁵ mod 561 Adım Adım
2³⁵ mod 561 hesaplanacak. 35 = 32 + 2 + 1 olduğundan 2³⁵ = 2³² · 2² · 2¹. Başta sonuc = 1, a = 2.
Bit 0 = 1: sonuc = 1 · 2 mod 561 = 2 (2¹ katıldı). Sonra a = 2² mod 561 = 4.
Bit 1 = 1: sonuc = 2 · 4 mod 561 = 8 (2² katıldı). Sonra a = 4² mod 561 = 16.
Bit 2 = 0: sonuc değişmez (8). Yalnızca kare alınır: a = 16² mod 561 = 256.
Bit 3 = 0: sonuc değişmez (8). Yalnızca kare alınır: a = 256² mod 561 = 460.
Bit 4 = 0: sonuc değişmez (8). Yalnızca kare alınır: a = 460² mod 561 = 103.
Bit 5 = 1: sonuc = 8 · 103 mod 561 = 263 (2³² katıldı). Sonra a = 103² mod 561 = 511.
d = 0: döngü bitti. return 263 = 2³⁵ mod 561; 34 yerine yalnızca 6 kare + 3 çarpma.
static long usMod(long a, long d, long n) { long sonuc = 1; a %= n; while (d > 0) { if ((d & 1) == 1) // bit 1 ise sonuc = sonuc * a % n; a = a * a % n; // kare al d >>= 1; // sonraki bit } return sonuc; }
Monte Carlo Algoritmaları
Miller–Rabin Örnekleri
| n | n − 1 | a | ad, a2d, … (mod n) | sonuç |
|---|---|---|---|---|
| 61 | 22 · 15 | 2 | 11, 60 | geçti (asal olabilir) |
| 221 | 22 · 55 | 174 | 47, 220 | geçti (asal olabilir) |
| 221 | 22 · 55 | 137 | 188, 205 | bileşik (a tanık) |
| 561 | 24 · 35 | 2 | 263, 166, 67, 1 | bileşik (a tanık) |
- 61 asaldır: dizi n − 1 = 60'a ulaşır.
- 221 = 13 · 17: a = 174 bir güçlü yalancıdır (dizi 220'ye ulaşır); a = 137 ise tanıktır. Bu yüzden birden çok tur gerekir.
- 561 = 3 · 11 · 17 bir Carmichael sayısıdır: 2560 ≡ 1, yani Fermat testi aldanır. Miller–Rabin ise 67² ≡ 1 olduğunu görür: 67, 1'in ±1 dışında bir karekökü → bileşik.
Monte Carlo Algoritmaları
Karger Min-Kesim Algoritması
Başlangıç: 6 düğüm, 8 kenar. Minimum kesim 2'dir (ör. {3, 4} | geri kalanı). Koyu düğüm: son büzmede oluşan süper düğüm.
Rastgele kenar (0, 2) büzüldü: uçları tek süper düğümde birleşti, aradaki kenarlar (öz-döngüler) silindi, paralel kenarlar (×k) korunur. Kalan: 7 kenar.
Rastgele kenar (1, 5) büzüldü: uçları tek süper düğümde birleşti, aradaki kenarlar (öz-döngüler) silindi, paralel kenarlar (×k) korunur. Kalan: 6 kenar.
Rastgele kenar (3, 4) büzüldü: uçları tek süper düğümde birleşti, aradaki kenarlar (öz-döngüler) silindi, paralel kenarlar (×k) korunur. Kalan: 5 kenar.
Rastgele kenar (0, 1) büzüldü: uçları tek süper düğümde birleşti, aradaki kenarlar (öz-döngüler) silindi, paralel kenarlar (×k) korunur. Kalan: 2 kenar. İki süper düğüm kaldı → bulunan kesim = 2 (minimum, başarılı çalıştırma).
- Problem: çizgeyi iki parçaya ayıran en az kenarlı kesim (global min-cut).
- Algoritma: 2 düğüm kalana dek düzgün rastgele bir kenarı büz; kalan kenar sayısı bir kesimdir.
- Bir çalıştırma minimum kesimi en az 2/(n(n−1)) olasılıkla bulur (n = 6: ≥ 1/15). Bu çizgede 200 000 benzetimde gözlenen ≈ 0,46.
- Çıktı yanlış (daha büyük kesim) olabilir → Monte Carlo. Ör. ilk kenarlar (1,2), (4,5), (3,4), (0,1) seçilirse {0,1,2} | {3,4,5} kesimi, 3 kenar.
- n(n−1)/2 · ln n tekrar → başarısızlık ≤ 1/n; toplam O(n4 log n) (basit uygulama).
Monte Carlo Algoritmaları
Diğer Uygulamalar
Rastgele zamanlama (iş atama) ile benzetimli tavlama ve genetik algoritma gibi metasezgiseller de rastgeleliği arama için kullanır; metasezgiseller optimuma yakınsamayı garanti etmez.
Monte Carlo Algoritmaları
Sözde Rastgele Sayılar
- Bilgisayar gerçek rastgelelik yerine sözde rastgele (pseudo-random) sayı üretir: deterministik ama rastgele görünen bir dizi.
- Doğrusal eşlik üreteci (LCG): Xk+1 = (a · Xk + c) mod m.
java.util.Random: a = 25214903917, c = 11, m = 248. - Aynı tohum (seed) aynı diziyi verir:
new Random(42)ile çalıştırmalar tekrarlanabilir (hata ayıklama, deney). - Kriptografi için
SecureRandom; çok iş parçacıklı koddaThreadLocalRandom.
zar.nextInt(n)→ 0 … n − 1alt + zar.nextInt(ust − alt + 1)→ alt … ustzar.nextDouble()→ [0, 1)zar.nextInt(6) + 1→ zar atışı: 1 … 6
Özet
Özet
| Konu | Hatırlanacaklar |
|---|---|
| Rastgele algoritma | girdi + rastgele bitler; süre/çıktı rastgele değişken; beklenti algoritmanın seçimleri üzerinden |
| Las Vegas | her zaman doğru, süre rastgele: QuickSort, QuickSelect, BogoSort |
| Monte Carlo | süre sınırlı, küçük hata olasılığı; tekrarla qk'ya iner |
| Fisher–Yates | j = nextInt(i + 1), Θ(n), n! sonuç eşit olasılıklı; saf karıştırma yanlı |
| BogoSort | p = 1/n!, beklenen Θ(n · n!), en kötü sınırsız |
| Rastgele QuickSort | beklenen ≈ 1,39 n log₂ n karşılaştırma, her girdi için O(n log n); en kötü O(n²) |
| Miller–Rabin | n − 1 = 2sd; hata ≤ 4−k; "bileşik" kesin |
| Karger | rastgele kenar büzme; başarı ≥ 2/(n(n−1)); çok kez tekrarla |
| π tahmini | 4 · iç / n; hata ∝ 1/√n |
Özet
Etkileşimli Simülatörler
Özet
Sık Yapılan Hatalar
nextInt(n) ile takas yanlıdır (nn yol, n! permütasyon). Doğrusu nextInt(i + 1).int ile x * x % n, n > 46 340 için taşar. long, Math.multiplyHigh ya da BigInteger.modPow kullanın.Random paylaşın; Karger'de kenarı düzgün seçin (önce düğüm, sonra komşu seçmek düzgün değildir).Özet
Örnek Problemler
- Fisher–Yates
[1, 2, 3, 4]dizisine uygulanıyor; i = 3, 2, 1 için çekilen j değerleri 1, 2, 0. Sonuç nedir? - 5 farklı öğeli bir dizide BogoSort'un ilk karıştırmada bitme olasılığı ve beklenen karıştırma sayısı nedir?
- Rastgele QuickSort'ta en küçük ve en büyük öğe hangi olasılıkla karşılaştırılır? Sıralı hâlde komşu iki öğe?
- Miller–Rabin: n = 25 için a = 7 ve a = 2 tabanlarıyla testi uygulayın.
- Monte Carlo ile 1000 noktanın 787'si çeyrek dairenin içine düştü. π tahmini nedir?
Cevapları göster
- i = 3, j = 1 → [1, 4, 3, 2]; i = 2, j = 2 → değişmez; i = 1, j = 0 → [4, 1, 3, 2].
- P = 1/5! = 1/120; beklenen karıştırma sayısı 120 (geometrik dağılım).
- z1 ile zn: 2/n (ilk pivot bu ikisinden biri olmalı). Komşular zi, zi+1: 2/2 = 1, her zaman karşılaştırılır.
- 24 = 23 · 3. a = 7: 73 ≡ 18, 18² ≡ 24 = n − 1 → geçer (7, 25 için güçlü yalancı). a = 2: 8, 14, 21 → 24 hiç görünmez → bileşik.
- π ≈ 4 · 787/1000 = 3,148.
Özet
Alıştırmalar
[3, 8, 2, 5, 1, 4, 7, 6]dizisindebolçağrılıyor ver = 5(pivot 4) çekiliyor. Parçalama sonrası dizi ve dönüş değeri nedir?- Sıralı 8 öğeli bir dizide ilk öğeyi pivot seçen QuickSort kaç karşılaştırma yapar?
- Miller–Rabin'de hata olasılığını 10−6'nın altına indirmek için en az kaç tur gerekir?
- Karger'i 6 düğümlü bir çizgede (başarı ≥ 1/15) kaç kez tekrarlarsanız başarısızlık olasılığı 1/6'nın altına iner?
- Başarı olasılığı 1/3 olan ve sonucu doğrulanabilen bir Monte Carlo algoritmasını Las Vegas'a çevirin. Beklenen tekrar sayısı nedir?
Cevapları göster
- Pivot sona: [3, 8, 2, 5, 1, 6, 7, 4]; ≤ 4 olanlar 3, 2, 1 sola alınır → [3, 2, 1, 4, 8, 6, 7, 5], dönüş 3.
- Her düzeyde parça bir küçülür: 7 + 6 + … + 1 = n(n − 1)/2 = 28.
- 4−k < 10−6 → k ≥ 10 (4−10 ≈ 9,5 · 10−7).
- (14/15)T ≤ e−T/15 ≤ 1/6 → T ≥ 15 ln 6 ≈ 26,9 → 27 tekrar yeterli.
- Doğrulama başarılı olana kadar tekrar et: hep doğru yanıt (Las Vegas); beklenen tekrar 1/(1/3) = 3.
Özet
Kaynaklar
- R. Motwani ve P. Raghavan, Randomized Algorithms, Cambridge University Press, 1995.
- M. Mitzenmacher ve E. Upfal, Probability and Computing, 2. baskı, Cambridge University Press, 2017.
- Cormen, Leiserson, Rivest ve Stein, Introduction to Algorithms, 4. baskı, 2022 (Bölüm 5, 7, 9, 31).
- C. A. R. Hoare, "Quicksort", The Computer Journal 5(1), 1962.
- M. O. Rabin, "Probabilistic Algorithm for Testing Primality", Journal of Number Theory 12(1), 1980.
- D. R. Karger, "Global Min-cuts in RNC, and Other Ramifications of a Simple Min-Cut Algorithm", SODA, 1993.
- D. E. Knuth, The Art of Computer Programming, Cilt 2, 3. baskı, 1997 (Bölüm 3.4.2: karıştırma).