T: tema · Z: kodu büyüt · S: konuşmacı notları · F: tam ekran · Esc: genel bakış · ⌂ ders haritası
OYUNLARDA YAPAY ZEKÂ · VERİ YAPILARI
Arama
Algoritmaları
Searching — sıralı arama · ikili arama · ikiye bölme · loot tabloları
PRESS ▶ TO START

Bu derste oyunun haritası 🗺️

  1. Arama problemi — ne arıyoruz, “yok” nasıl denir? search problem
  2. Sıralı arama — baştan sona tek tek sequential search
  3. İkili arama — her adımda yarısını at binary search
  4. Oyunlarda ikili arama — XP tabloları, loot sandıkları, animasyon eğrileri
  5. İkiye bölme — hızlı mermi duvarın içinden neden geçer? bisection
  6. ⚙️ Perde arkası & ötesi — önbellek, enterpolasyon araması, sembol tabloları
🎮 Bu dersin sonunda…

…1 milyon kayıt içinde bir şeyi 20 adımda bulabilecek, bir loot sandığının nasıl çalıştığını ve hızlı bir merminin duvarı neden “ıskaladığını” açıklayabileceksiniz.

🤔 ISINMA SORUSU

Kâğıttan bir sözlükte “kelebek” kelimesini
nasıl bulursunuz?

İlk sayfadan başlayıp kelimeleri tek tek mi okursunuz?

Tabii ki hayır! Ortalardan bir yerden açarsınız: “Burası m harfi, k daha önce” → sol yarıya geçersiniz…

Bu sezginin adı: ikili arama binary search. Bugün onu bir algoritmaya dönüştüreceğiz.

Peki sözlük sırasız olsaydı? 😱 O zaman tek yol baştan sona okumak: sıralı arama.

Oyunlarda arama her yerde

🎒
Envanter“Ejder Kılıcı çantada var mı?”
📈
Seviye tablosu“2700 XP kaçıncı seviye?”
🎁
Loot tablosu%2 efsanevi, %10 epik… hangi eşya düştü?
🎞️
Animasyon eğrilerit = 1,37 sn hangi iki anahtar kare arasında?
💥
Çarpışma anıMermi duvara tam olarak ne zaman değdi?
🧭
Yol bulmaOyun YZ’de “arama” = olası hamleler arasında arama (A*, minimax). Temel fikir aynı: adayları akıllıca ele.

Mini sözlük (1/2)

searcharamaBir koleksiyonda aranan değeri bulmak
keyanahtarAradığımız değer (bir sayı, bir ad, bir ID…)
search hit / missbaşarılı / başarısız aramaAranan bulundu / koleksiyonda yok
indexindeksElemanın dizideki sıra numarası (0’dan başlar)
sequential (linear) searchsıralı (doğrusal) aramaBaştan sona tek tek bakmak
binary searchikili aramaSıralı veride her adımda yarısını atmak
sortedsıralıKüçükten büyüğe dizilmiş (ikili aramanın ön koşulu!)

Mini sözlük (2/2)

invariantdeğişmezDöngü boyunca hep doğru kalan cümle
logarithmlogaritma“Kaç kez ikiye bölebilirim?” sorusunun cevabı
sentinelnöbetçiDöngüyü kendiliğinden durduran, sona konan özel eleman
predicatekoşul fonksiyonuDoğru/yanlış döndüren fonksiyon: “canı 20’den az mı?”
lower boundalt sınırAranandan büyük ya da eşit olan ilk elemanın yeri
bisectionikiye bölmeBir aralığı yarıya bölerek bir sınırı bulmak
cumulative sumkümülatif (birikimli) toplamHer eleman = kendisine kadar olanların toplamı
LEVEL 0
Arama Problemi
the search problem — ne arıyoruz, “yok” nasıl söylenir?
  • arama problemi
  • sıralı arama
  • ikili arama
  • oyunlarda ikili arama
  • ikiye bölme (bisection)
  • perde arkası & ötesi

Problem

Girdi: N elemanlı bir dizi a ve aranan bir anahtar key

Çıktı: key dizideyse indeksi, değilse “yok” işareti (genelde −1)

  • Bulunursa: başarılı arama search hit
  • Bulunamazsa: başarısız arama search miss
Maliyet modeli cost modelAlgoritma analizi dersindeki gibi: saniyeyi değil, kaç kez a[i] ile karşılaştırdığımızı sayacağız.
🎮 Örnek

a = [ 12, 45, 7, 88, 23 ] (envanterdeki eşya ID’leri)

  • search(a, 88) → 3
  • search(a, 50) → −1

Neden −1? Çünkü geçerli indeksler 0, 1, 2… −1 hiçbir zaman gerçek bir indeks olamaz → “yok” demek için güvenli.

🎒 Ön bilgi: “bulunamadı” nasıl söylenir? return value

Fonksiyon bir değer döndürür (return); çağıran taraf bu değeri bir değişkene alıp kontrol eder.

  • −1: “indeks yok” işareti (C#, JS, kendi kodlarımız)
  • None / null: “nesne yok” (bir düşman, bir eşya ararken)
  • Hata fırlatmak exception: Python’un list.index’i bulamazsa programı durdurur!
⚠️ En sık hataDönen değeri kontrol etmeden kullanmak: a[search(a, 50)] → a[-1]! Python’da bu son eleman demektir: hata bile vermez, yanlış eşyayı verir. 😱
LEVEL 1
Sıralı Arama
sequential (linear) search — en basit, her yerde çalışan yöntem
  • arama problemi
  • sıralı arama
  • ikili arama
  • oyunlarda ikili arama
  • ikiye bölme (bisection)
  • perde arkası & ötesi

Fikir: baştan sona tek tek bak

  1. i = 0’dan başla.
  2. a[i] aranan mı? Evetse i’yi döndür.
  3. Değilse bir sonrakine geç.
  4. Dizi bittiyse −1 döndür.
👍 ArtısıDizinin sıralı olması gerekmez. Bağlı listede de çalışır. Kodu 4 satır.

Sıralı arama — animasyon (sırasız dizi)

Kaç karşılaştırma? 📐

  • En iyi best case: aranan ilk elemanda → 1
  • En kötü worst case: aranan sonda ya da hiç yok → N
  • Ortalama (bulunan anahtar her konumda eşit olasılıkla):

\( \dfrac{1 + 2 + \dots + N}{N} = \dfrac{N(N+1)/2}{N} = \dfrac{N+1}{2} \sim \dfrac{N}{2} \)

1’den N’e kadar toplam = \( N(N+1)/2 \) (Gauss’un küçükken bulduğu söylenen formül).

Önerme Sıralı arama, N elemanlı bir dizide başarısız aramada tam N, başarılı aramada ortalama ~N/2 karşılaştırma yapar.

Yani süre N ile doğru orantılı: N iki katına çıkarsa süre de iki katına çıkar. Buna doğrusal linear zaman denir.

🔗 Başka gözle: etkileşimli anlatımlar ve yazılar

Aynı konuyu başka bir anlatımla, kendi elinizle oynayarak görmek çok işe yarar. Kartlar yeni sekmede açılır; çoğu İngilizce ama görsel ve etkileşimli.

Quiz 1 · sıralı arama
1000 elemanlı sırasız bir dizide, dizide olmayan bir değeri sıralı aramayla ararsak kaç karşılaştırma yapılır?
“Yok” diyebilmek için her elemana bakmak zorundayız: belki aradığımız en sondadır. Başarısız arama her zaman N karşılaştırma ister. Ortalama ~N/2 sadece başarılı aramalar için geçerli.

Hazır fonksiyonlar da sıralı arama yapar!

dil“var mı?”“nerede?”koşulla bul
Pythonx in listeliste.index(x)for + if · next(...)
C#list.Contains(x)list.IndexOf(x)list.Find(...)
JavaScriptarr.includes(x)arr.indexOf(x)arr.find(...)
⚠️ Tek satır ≠ hızlıBu fonksiyonların hepsi içeride bir for döngüsüdür: N karşılaştırma. Oyunda Update() içinde (saniyede 60 kez) 1000 düşmanlık bir listede Contains çağırmak = saniyede 60.000 karşılaştırma… ve her düşman bunu yapıyorsa 60 milyon!

🎒 Ön bilgi: koşulla arama — geleneksel ve modern predicate

“Canı 20’den az olan ilk düşmanı bul.” Aranan bir değer değil, bir koşul. (enemies: düşman nesnelerinin listesi; her düşmanın hp alanı var.)

Doğru/yanlış döndüren küçük fonksiyona koşul fonksiyonu predicate denir. Modern yazımda bunu lambda / ok fonksiyonu olarak veririz. İkisi de aynı işi yapar: sıralı arama.

⚙️ Nöbetçi hilesi sentinel

Normal sıralı aramada döngü her adımda iki soru sorar:

  1. i < N mi? (dizi bitti mi?)
  2. a[i] == key mi?

Hile: aranan değeri dizinin sonuna ekle. Artık döngü mutlaka durur → 1. soruya gerek yok!

Döngü bitince tek bir kontrol: durduğumuz yer nöbetçinin kendisi mi?

Klasik bir optimizasyon (Knuth’un kitaplarında da var). Modern işlemcilerde kazanç küçüktür; ama “iç döngüden gereksiz kontrolü çıkar” fikri her yerde işe yarar.

⚙️ Nöbetçili sıralı arama — kod

🎒 C#’taki koşul ? x : y: “koşul doğruysa x, değilse y” (üçlü ifade ternary operator). Altındaki yorumda geleneksel if/else hali var.

🎮 Sık arananı öne al move-to-front

Oyuncunun büyü kitabında 200 büyü var ama savaşta hep aynı 5’ini kullanıyor.

Fikir: bir büyü bulunduğunda onu listenin başına taşı. Sık kullanılanlar hep önde durur → sıralı arama çoğu zaman 1–5 adımda biter.

Buna “kendini düzenleyen liste” self-organizing list denir. Aynı fikir: “son kullanılan dosyalar”, tarayıcı geçmişi, işlemci önbelleklerinin LRU politikası.

aramaliste (önce → sonra)adım
—Ateş · Buz · Şimşek · İyileş · Kalkan
İyileşİyileş · Ateş · Buz · Şimşek · Kalkan4
İyileşİyileş · Ateş · Buz · Şimşek · Kalkan1
KalkanKalkan · İyileş · Ateş · Buz · Şimşek5
İyileşİyileş · Kalkan · Ateş · Buz · Şimşek2
Quiz 2 · sıralı arama
Sıralı bir bağlı listede ikili arama yapmak neden pratik değildir?
İkili arama, a[mid]’e tek adımda atlayabilmeye dayanır (rastgele erişim random access). Dizide bu bir adres hesabıdır; bağlı listede ise ortadaki düğüme ulaşmak için N/2 düğüm yürümek gerekir → her “zıplama” zaten sıralı arama kadar pahalı.
LEVEL 2
İkili Arama
binary search — her soruda adayların yarısını at
  • arama problemi
  • sıralı arama
  • ikili arama
  • oyunlarda ikili arama
  • ikiye bölme (bisection)
  • perde arkası & ötesi
🤔 ISINMA: 20 SORU

Aklınızdan dünyadaki herhangi bir insanı tutun.
Ben sadece evet/hayır soruları soracağım.

Kaç soruda bulabilirim? 100? 1000? 1 milyon?

Her soru adayları yarıya indirirse: 2³³ ≈ 8,6 milyar ≥ dünya nüfusu → 33 soru yeter!

“Akinator” adlı ünlü oyun, aklınızdaki karakteri genellikle 20 civarı soruda bulur. Bu bölümün sihirli kelimesi: logaritma.

Fikir: ortadakine bak, yarısını at

  1. Aralık: tüm dizi, lo = 0, hi = N − 1
  2. Ortadaki elemana bak: mid
  3. Aranan küçükse → sol yarıda devam: hi = mid − 1
  4. Aranan büyükse → sağ yarıda devam: lo = mid + 1
  5. Eşitse → bulundu! Aralık boşalırsa (lo > hi) → yok
012345678910111213141. adım381217212630354144505763707835 < 63 → sağ2. adım381217212630354144505763707857 < 63 → sağ3. adım381217212630354144505763707870 > 63 → sol4. adım3812172126303541445057637078bulundu ✔

Skor tablosunda 63’ü arıyoruz: 15 eleman, 4 adım. Turuncu = mid, soluk = atılan yarı.

⚠️ İki ön koşul
  1. Dizi sıralı olmalı.
  2. a[mid]’e tek adımda erişebilmeliyiz (dizi ✔, bağlı liste ✘).
💡 Bedava değilSıralama da bir maliyet! Tek bir arama için diziyi sıralamaya değmez. Ama bir kez sıralayıp binlerce kez arayacaksak → kesinlikle değer.

İkili arama — animasyon

İz tablosu trace — başarılı arama: P

kırmızı = a[mid] · siyah = hâlâ aday (lo…hi) · gri = elendi

İz tablosu — başarısız arama: Q

Aralık boşaldığında lo, Q’nun eklenmesi gereken yeri gösterir — birazdan çok işimize yarayacak!

🎒 Ön bilgi: tam sayı bölmesi integer division

mid bir indeks olduğu için tam sayı olmalı. Ama her dilde / farklı davranır:

dil7 / 2tam sayı bölmesidikkat!
Python3.57 // 2 → 3a[7 / 2] → ❌ TypeError: list indices must be integers
C#3 (iki int → tam sayı!)7 / 2 → 37.0 / 2 → 3.5 · (float)7 / 2 → 3.5
JavaScript3.5Math.floor(7 / 2) → 3a[3.5] → undefined (hata bile yok! 😱)

C# öğrencilerinin klasik hatası: int can = 7; float oran = can / 2; → 3 (3.5 değil), çünkü bölme önce tam sayı olarak yapılır.

İkili arama — kod

Neden (lo + hi) / 2 değil de lo + (hi − lo) / 2? → Birkaç slayt sonra, 9 yıl saklı kalan bir hata hikâyesi. 🕵️

Neden doğru çalışıyor? Değişmez invariant

< key (elendi)
aday aralığı a[lo…hi]
> key (elendi)
Değişmez“key dizideyse, mutlaka a[lo…hi] aralığındadır.”
  • Başta doğru: aralık tüm dizi.
  • Her adımda korunur: key < a[mid] ise dizi sıralı olduğundan mid ve sağındakilerin hepsi key’den büyük → atmak güvenli.
  • Sonda: aralık boşaldıysa (lo > hi), key hiçbir yerde olamaz → −1 doğru cevap. ✔

Özyinelemeli ikili arama recursive

“Yarıda ara” cümlesi aslında: aynı problemi daha küçük bir aralıkta çöz → özyineleme!

  • Temel durum base case: aralık boş → −1
  • Her çağrı, yığına stack bir kare ekler (yığınlar dersi!)
  • Derinlik en fazla ~lg N → 1 milyar elemanda bile ~30 kare. Güvenli. ✔

📐 Kaç karşılaştırma? Logaritma logarithm

Önermeİkili arama N elemanlı sıralı bir dizide en fazla \( \lfloor \lg N \rfloor + 1 \) karşılaştırma yapar.
Kanıt fikri: her karşılaştırma aday sayısını en az yarıya indirir: N → N/2 → N/4 → … → 1.
🧠 Akılda tutma hilesi\( 2^{10} \approx 1000 \) · \( 2^{20} \approx \) 1 milyon · \( 2^{30} \approx \) 1 milyar.
\( \lg N = \log_2 N \) = N’i kaç kez yarıya bölebilirsin?

🎮 Sayı tahmin oyunu

Bilgisayar modunda 1–100 arası bir sayı tutun ve dürüst cevap verin. Bilgisayar ikili arama yapıyor: en fazla 7 tahminde bulur, çünkü \( 2^7 = 128 \ge 100 \).

N büyüdükçe: sıralı arama vs ikili arama 📈

🎬 Ara: ikili arama, 2 dakikada

Binary Search Algorithm in 100 Seconds
Fireship · 2 dk 20 sn · YouTube’da aç

Sayı tahmin oyunundaki “ortadan böl” fikrinin kodla birlikte hızlı özeti; lo, hi ve mid’in nasıl güncellendiğini izleyin.

🤔 İzlerkenVideodaki kod döngüyle mi özyinelemeyle mi yazılmış? mid hesabında taşma (lo + hi) / 2 tuzağına dikkat ediliyor mu? Sıralı olmayan bir dizide ne olurdu?
Quiz 3 · ikili arama
1.000.000 elemanlı sıralı bir dizide ikili arama en kötü durumda yaklaşık kaç karşılaştırma yapar?
\( 2^{20} \approx 1.048.576 \) → 20 kez yarıya bölünce tek eleman kalır. Sıralı arama ise en kötü 1.000.000 karşılaştırma yapardı: 50.000 kat fark!
Quiz 4 · ikili arama · kod
Koddaki while (lo <= hi) yerine while (lo < hi) yazarsak ne olur?
Aralık tek elemana indiğinde (lo == hi) döngü o elemana hiç bakmadan biter. Örn. [7] dizisinde 7’yi ararsak hemen −1 döner. Bu tür “bir eksik/bir fazla” hatalarına off-by-one hatası denir. Kod laboratuvarında deneyin!
Quiz 5 · ikili arama · kod
mid = lo + (hi - lo) / 2 yerine mid = lo yazarsak ne olur?
Her adımda sadece bir eleman (en soldaki) elenir: lo = mid + 1. Değişmez korunduğu için sonuç doğrudur, ama aday kümesi yarıya değil birer birer azalır → N karşılaştırma. “Yarıya bölmek” hızın kaynağıdır, doğruluğun değil.

📜 Basit görünen, yazması zor bir algoritma

1946 → 1962Knuth’a göre ikili arama ilk kez 1946’da yayımlandı; ama her N için doğru çalışan ilk sürüm ancak 1962’de çıktı.
%90Jon Bentley, profesyonel programcılara ikili arama yazdırdığında çoğunun kodunda hata buldu (Programming Pearls).
2006Joshua Bloch: Java’nın kendi kütüphanesindeki ikili arama 9 yıl boyunca hatalıydı! Hata: mid = (lo + hi) / 2
⚙️ Tam sayı taşması integer overflowC#’ta int 32 bittir: en büyük değer 2.147.483.647. Bir fazlası en küçük negatif sayıya “sarar”. Oyunlarda da çok görülür (efsane: Civilization’daki “nükleer Gandhi”).

🧪 Kod laboratuvarı: ikili arama (otomatik testli)

Her değişiklikten sonra çalıştır: kodun 250+ rastgele testten geçiyor mu?
  1. 6. satırda <= yerine < yaz. Hangi test başarısız oldu?
  2. 9. satırda hi = mid - 1 yerine hi = mid yaz. Ne oldu, neden?
  3. 7. satırı const mid = lo; yap. Testler geçiyor mu? Okuma sayısı ne diyor?
  4. Kendi sıralı arama fonksiyonunu yaz: testler geçer mi, uyarı çıkar mı?

🐍 Aynı laboratuvar — Python

Python tarayıcıda çalışır (ilk açılışta internet gerekir).
  1. 7. satırda // yerine / yaz. Hata mesajını oku: neden?
  2. return -1 satırını sil. Python bulamayınca ne döndürüyor?
  3. Özyinelemeli sürümü yaz (önceki slayttaki gibi, lo ve hi parametreli bir yardımcı fonksiyonla).

⚙️ Küçük dizilerde sıralı arama daha hızlı olabilir!

Karşılaştırma sayısı her şey değildir. Donanım da önemli:

  • Önbellek cache: işlemci bellekten 64 baytlık bloklar (önbellek satırı) getirir = 16 tane int. Sıralı arama bu blokları sırayla okur → çok hızlı. İkili arama bellekte zıplar → büyük dizilerde her zıplama bir önbellek ıskası.
  • Dal tahmini branch prediction: sıralı aramanın if’i neredeyse hep “hayır” → işlemci kolayca tahmin eder. İkili aramanın sol/sağ kararı ise yazı-tura gibi → sık yanılır.
⚙️ Pratikte

Birkaç düzine elemana kadar düz sıralı arama genelde ikili aramayı geçer. Hızlı kütüphaneler bu yüzden önce ikili aramayla aralığı daraltıp, küçük kalan kısımda sıralı aramaya geçer.

Ders: “Büyük-O” büyük N için doğrudur; küçük N’de sabitler ve donanım kazanır. Ölçmeden karar vermeyin (algoritma analizi dersindeki bilimsel yöntem!).

LEVEL 3
Oyunlarda İkili Arama
XP tabloları · loot sandıkları · animasyon eğrileri
  • arama problemi
  • sıralı arama
  • ikili arama
  • oyunlarda ikili arama
  • ikiye bölme (bisection)
  • perde arkası & ötesi

Aranan yoksa: “nereye eklenirdi?” lower bound · rank

Çoğu zaman tam eşitlik değil, sınır ararız:

  • lower bound: a[i] ≥ key olan ilk i
  • = key’den küçük kaç eleman var? (rank)
  • = key sıralı diziye nereye eklenmeli?

🎮 Skor tablosu: yeni skor 1530 → kaçıncı sıraya girer?

Fark: aralık “yarı açık” [lo, hi); döngü lo < hi; eşit bulunca durmadan sola devam ederiz. Sonunda lo = cevap.

Quiz 6 · oyunlarda ikili arama
a = [1, 3, 3, 3, 5] dizisinde 3 aranıyor. Klasik ikili arama ve lower_bound hangi indeksleri döndürür?
Klasik ikili arama herhangi bir 3’ü bulur: ilk mid = 2 ve a[2] = 3 → hemen döner. lower_bound ise eşit bulsa bile sola bakmaya devam eder ve ilk 3’ün yerini (1) verir. Tekrar eden anahtarlarda bu fark önemlidir: “3 puanlı oyunculardan ilki kim?”

🎮 XP → seviye tablosu

Kutular: her seviyenin başladığı XP eşiği (sıralı!). Aranan: eşiği oyuncunun XP’sini geçmeyen en büyük eşik (floor). 16 seviyede en fazla 5 adım; 1000 seviyelik bir MMO’da bile 10 adım.

🎁 Loot tablosu nasıl çalışır? weighted random

Ağırlıklar: Sıradan 60 · Nadir 28 · Epik 10 · Efsanevi 2

  1. Kümülatif toplam cumulative sum al: [60, 88, 98, 100]
  2. 0 ile 100 arası rastgele bir r çek: ör. r = 93.4
  3. r’den büyük ilk kümülatif değeri ikili aramayla bul: 98 → indeks 2 → Epik!

Neden doğru? r’nin her aralığa düşme olasılığı, o aralığın genişliği ile orantılı: [88, 98) aralığı 10 birim → %10.

🎁 Canlı demo: sandık açalım

🎞️ Animasyon eğrileri: zamanı hangi kareler arasında?

Bir animasyon eğrisi, zamana göre sıralı anahtar karelerden keyframes oluşur: (0 sn → 0), (0,5 sn → 2), (1,2 sn → 1)…

t = 0,8 sn’deki değer? → t’yi çevreleyen iki kareyi ikili aramayla bul, aralarında doğrusal enterpolasyon yap.

Unity’nin AnimationCurve.Evaluate, Godot’nun Curve’ü ve her animasyon sistemi bunu yapar — her karede, her kemik için!

🎒 lerplerp(a, b, t) = a + (b − a) · t → t = 0’da a, t = 1’de b, aradaki değerlerde ikisinin arası. Oyun programlamanın en çok kullanılan formülü.

Hazır ikili arama fonksiyonları

🎒 C#’taki ~Bulunamazsa Array.BinarySearch “eklenmesi gereken yer”i bit tersine çevirip negatif bir sayı olarak döndürür (−1 ile karışmasın diye). ~j bunu geri çevirir. Kural: sonuç negatifse yok, ~sonuç = ekleme yeri.

🧪 Kod laboratuvarı: lower bound’u kendin yaz

İpuçları: aralığı [lo, hi) yap (hi = a.length) · döngü lo < hi · a[mid] < key ise lo = mid + 1, değilse hi = mid · sonunda lo döndür. Takılırsan “lower bound” slaytına bak.
LEVEL 4
İkiye Bölme
bisection — dizide değil, “cevabın kendisinde” ikili arama
  • arama problemi
  • sıralı arama
  • ikili arama
  • oyunlarda ikili arama
  • ikiye bölme (bisection)
  • perde arkası & ötesi

Fikir: “evet/hayır” sorusu bir noktada değişiyorsa

İkili arama sadece dizilerde çalışmaz. Bir soru düşünün: cevabı bir noktaya kadar hep hayır, sonra hep evet olsun:

✘ ✘ ✘ ✘ ✘ ✘ ✔ ✔ ✔ ✔ ✔

✘1✘2✘3✘4✘5✘6✘7✘81✘9✘103✔114✔122✔13✔14✔15✔16h = zıplama gücü; mavi = deneme sırası (8, 12, 10, 11) → sınır h = 11

Böyle bir koşula monoton monotonic denir. Sınırı ikili aramayla buluruz: ortaya bak, ✘ ise sağa, ✔ ise sola.

Aralık sürekli bile olabilir (zaman, mesafe, açı…): her adımda aralık yarıya iner → 20 adımda milyonda bir hassasiyet.

🎮 Örnek sorular
  • Mermi t anında duvara değmiş mi?
  • Zıplama gücü h ile platforma yetişiliyor mu?
  • Kaçıncı sürümde oyun çökmeye başladı?
  • Zorluk d’de test oyuncularının yarısından fazlası kaybediyor mu?

💥 Hızlı mermi neden duvarın içinden geçer? tunneling

İkiye bölme — kod

🎒 cond bir fonksiyon parametresidir: “sorulacak soruyu” dışarıdan veririz (callback · predicate). Aynı first_true her türlü “ne zaman/ne kadar?” sorusu için çalışır.

📜 Hangi sürümde bozuldu? git bisect

Oyununuz dün akşam akıcıydı, bugün 20 FPS. Aradaki 500 değişiklikten (commit) hangisi bozdu?

01234567891011121314151✔2✘3✔4✔0 iyi, 15 kötü biliniyor · mavi = deneme sırası · 4 denemede bozan commit: 11
  • Sırayla tek tek denemek: 500 derleme + test 😩
  • İkiye bölme: ortadaki sürümü dene → iyi mi kötü mü? → yarısını at… ~9 deneme (\( 2^9 = 512 \))

Git bunu hazır bir komut olarak sunar: git bisect. Siz sadece “iyi” ya da “kötü” dersiniz; ortadaki sürüme Git atlar.

🎮 Oyun tasarımındaTasarımcılar da bunu sezgisel olarak yapar: “Zıplama 10 birimken platforma ulaşılamıyor, 20’de çok kolay… 15? 12?” Her denemede aralık yarıya iner. Bilinçli yaparsanız daha az test oyunu harcarsınız!
Quiz 7 · ikiye bölme
Çarpışma anını 1 karelik aralıkta, milyonda bir kare hassasiyetle bulmak istiyoruz. İkiye bölme kaç adım sürer?
Her adım aralığı yarıya indirir: \( 2^{20} \approx 10^6 \) → 20 adımdan sonra aralık 1/1.048.576 kare. Aynı hassasiyeti kareyi milyon parçaya bölüp tek tek kontrol ederek almak 1 milyon adım sürerdi.
LEVEL 5
Perde Arkası & Ötesi
enterpolasyon araması · üstel arama · sembol tabloları
  • arama problemi
  • sıralı arama
  • ikili arama
  • oyunlarda ikili arama
  • ikiye bölme (bisection)
  • perde arkası & ötesi

Telefon rehberi gibi: enterpolasyon araması interpolation search

Rehberde “Zeynep”i ararken ortadan açmazsınız: sonlara yakın bir yerden açarsınız!

Fikir: aranan değerin aralıktaki oranına göre tahmin yap:

\( pos = lo + \dfrac{key - a[lo]}{a[hi] - a[lo]} \cdot (hi - lo) \)

enterpolasyon512182631394452586671179285932 bakışikili arama51218263139441525866712794853934 bakışaranan 79; altındaki sayı = kaçıncı bakış. İlk tahmin: 0 + (79 − 5)·13 / (93 − 5) = 10 (tam sayı bölmesi)
  • Veriler düzgün dağılmışsa: ~\( \lg \lg N \) adım — 1 milyar elemanda ~5 adım!
  • Ama veriler dengesizse (ör. 1, 2, 3, 4, 1000000): en kötü N adım 😬
💡 DersDaha akıllı tahmin = ortalamada daha hızlı, ama garanti yok. İkili arama hiçbir zaman ~lg N’den kötü olmaz. Oyunlarda genelde garanti tercih edilir: bir karenin bütçesi 16 ms!

Sonu bilinmeyen dizide: üstel arama exponential (galloping) search

Dizinin boyutunu bilmiyorsak (çok uzun bir kayıt, sürekli büyüyen bir liste) ya da aranan başa yakınsa:

  1. 1., 2., 4., 8., 16.… elemanlara bak (her seferinde iki katı).
  2. Aranandan büyük bir eleman bulunca dur: aranan son iki bakış arasında.
  3. O aralıkta ikili arama yap.

Toplam ~2 lg k adım (k = aranan elemanın konumu). Baştaki elemanlar için çok hızlı!

🐍 Gerçek dünyadaPython’un ve Java’nın sıralama fonksiyonları (Timsort) iki sıralı parçayı birleştirirken bu “dörtnala” galloping aramayı kullanır. Sıralama derslerinde tekrar karşılaşacağız!
★12481632bakışlar: 1, 2, 4, 8, 16, 32 → aranan ★ (19. konum) 16 ile 32 arasında; yeşil aralıkta ikili arama

Sıralı dizi bir “sözlük” olabilir mi? symbol table

Oyunda anahtar → değer saklamak isteriz: eşya adı → adet, oyuncu ID → profil…

Anahtarları sıralı dizide tutarsak get ikili arama ile hızlı. Peki ekleme?

Yeni anahtarın yerini lg N’de buluruz ama ondan büyük herkesi bir sağa kaydırmak gerekir → ortalama N/2 taşıma.

yapıaramaekleme
sırasız dizi / listeN1
sıralı dizilg NN
❓ ikisinin de iyi yanılg Nlg N
🔜 İlerideki dersler

İkili arama ağaçları (BST): ikili aramanın “ortadakine bak, sola/sağa git” fikrini bir ağaca dönüştürür → arama ve ekleme ~lg N. Ağaçlar sunumu ▶

Hash tabloları: ortalama sabit zaman — ama sırayı kaybeder.

Özet tablo 📋

yöntemön koşulen iyiortalamaen kötü
sıralı arama— (her yerde)1N/2 (bulunursa)N
ikili aramasıralı + rastgele erişim1~lg N⌊lg N⌋ + 1
enterpolasyon aramasısıralı + düzgün dağılım1~lg lg NN
üstel aramasıralı (boyut bilinmese de)1~2 lg k (k = konum)
ikiye bölmemonoton koşulhassasiyet ε için ~lg(aralık / ε) adım

Değerler karşılaştırma sayısıdır.

Derin hikâye: “Nükleer Gandhi” — bir taşma efsanesi

  • Efsane: İlk Civilization’da (1991) barışçıl Gandhi’nin saldırganlık değeri en düşük, 1’di. Demokrasiye geçen ülkelerin saldırganlığı 2 azalıyordu; 1 − 2 = −1, işaretsiz 8 bitlik bir sayıda 255’e sarıyor ve Gandhi bir anda oyunun en saldırgan, nükleer silah kullanan lideri oluyordu.
  • Gerçek: Bu anlatı ilk kez 2012’de TV Tropes vikisine kanıtsız eklendi ve yayıldı. Civilization V’te (2010) Gandhi’nin nükleer silah kullanma eğilimi gerçekten yüksek ayarlanmıştı; efsanenin buradan beslenmiş olması muhtemel. Serinin yaratıcısı Sid Meier 2020’deki anı kitabında bu hatanın ilk oyunda mümkün olmadığını açıkladı.
  • Durum: Nükleer Gandhi → efsane. Tamsayı taşması → çok gerçek: Joshua Bloch 2006’da, Java’nın standart ikili aramasındaki (low + high) / 2 satırının çok büyük dizilerde taşıp negatif indeks ürettiğini ve hatanın JDK’da yaklaşık dokuz yıl fark edilmediğini yazdı. Aynı hata birçok kitapta ve mergesort uygulamasında da vardı.
Dersİyi bir hikâye, doğru bir hikâye olmayabilir: kaynağını sorun. Ama efsanenin “hissettirdiği” şey gerçek bir hata sınıfıdır: sayılar sonsuz değildir. İkili aramada orta noktayı low + (high − low) / 2 ile hesaplayın; oyunda can, para, saldırganlık gibi değerleri sınırlayın (clamp).

Kaynak: Wikipedia: Nuclear Gandhi · Bloch 2006 (Google Research)

🧰 Kütüphaneler ve araçlar

adplatformne yapar / sınırlarınasıl eklenir
Array.BinarySearch · List<T>.BinarySearchC# / UnityBulamazsa negatif sayı döner: ~sonuç eklenecek yerin indeksidir.yerleşik
bisectPythonbisect_left, bisect_right, insort; 3.10’dan beri key=.standart kütüphane
std::lower_bound · upper_bound · equal_rangeC++Sıralı aralıkta ilk ≥ / ilk > konum.#include <algorithm>
lodash sortedIndexJavaScriptJS’te yerleşik ikili arama yok; sıralı dizide ekleme yeri.npm install lodash

🧩 Oyunlarda ikili arama

  • Ağırlıklı ganimet tablosu: ağırlıkların önek toplamlarını tutun, [0, toplam) aralığında rastgele bir sayı seçin, ikili aramayla hangi eşyaya düştüğünü bulun: her çekiliş O(log n).
  • Deneyim → seviye: kümülatif XP tablosunda oyuncunun seviyesini bulmak.
  • Animasyon/eğri anahtar kareleri: t anına en yakın iki anahtar kare.
  • Cevap üzerinde ikili arama: “düşmanın canı en az ne olmalı ki oyuncu 3 vuruşta öldüremesin?” gibi tekdüze sorular.
Klasik hatalar
  • Orta nokta taşması (yukarıdaki hikâye).
  • Sonsuz döngü: lo = mid ile lo < hi birlikteyse.
  • Sıralı olmayan veride ikili arama.
  • C#’ta negatif dönüşü indeks sanmak.

🤖 Bu konuyu bir YZ kod asistanıyla yazarken

Sık yapılan hatalar — kontrol edin
  • (lo + hi) / 2 taşması
  • Bir fazla/eksik sınır hatası ve sonsuz döngü
  • BinarySearch’ün negatif dönüşünü indeks sanmak
  • Sıralanmamış listede arama
İyi bir istek (prompt) örneği

“Unity 6, C#. Ağırlıklı ganimet tablosu yaz: LootTable (eşya, ağırlık) listesiyle kurulur, önek toplamlarını bir kez hesaplar; Roll(System.Random rng) önek toplamlarında ikili aramayla eşyayı döndürür (Array.BinarySearch’ün ~ dönüşünü doğru kullan). 1 milyon çekilişle dağılımın ağırlıklarla uyumunu test eden NUnit testi ekle.”

  • Aralığın yarı açık mı ([lo, hi)) kapalı mı olduğunu yazdırın
  • Orta noktayı taşmasız isteyin
  • Sınır durumlarını (boş, tek, hepsi eşit, bulunamadı) test ettirin
  • Standart fonksiyon (bisect, BinarySearch) alternatifini sorun

🚀 Proje ve araştırma önerileri

  1. [kolay] Ganimet tablosu — Önek toplamı + ikili arama; 1 milyon çekilişte histogramı ağırlıklarla karşılaştırın.
  2. [kolay] XP eğrisi — Seviye tablosunu üretin ve XP’den seviyeyi ikili aramayla bulun.
  3. [orta] Cevap üzerinde ikili arama — Bir düşmanın “adil” can değerini simülasyon + ikili aramayla otomatik ayarlayın.
  4. [araştırma] Taşma avı — Kendi oyununuzdaki sayısal değerlerde taşma riskini tarayan küçük bir statik kontrol ya da test yazın.

📄 Akademik okumalar ve kaynaklar

Bloch 2006 · Extra, Extra — Read All About It: Nearly All Binary Searches and Mergesorts are Broken (Google Research Blog)
Dokuz yıl gizli kalan taşma.
Bentley 1986 · Programming Pearls (2. sütun: “Aha! Algorithms”, 4. sütun: “Writing Correct Programs”) (Addison-Wesley)
Profesyonellerin bile ikili aramayı doğru yazmakta zorlandığı deney.
Knuth 1998 · The Art of Computer Programming, Vol. 3, §6.2.1 (Addison-Wesley)
İkili aramanın tarihi ve çeşitleri.

Neler öğrendik? 🎒

  • Arama problemi: indeks ya da −1; başarılı / başarısız arama.
  • Sıralı arama: her yerde çalışır, N adım; hazır fonksiyonlar da böyle!
  • Nöbetçi, öne alma: küçük ama akıllı hileler.
  • İkili arama: sıralı dizi + ortadan bölme → ⌊lg N⌋ + 1.
  • Logaritma = “kaç kez yarıya?” · \( 2^{10} \approx 1000 \).
  • lower bound: “nereye eklenirdi?” — XP tabloları, loot sandıkları, animasyon eğrileri.
  • İkiye bölme: monoton koşul → çarpışma anı, git bisect.
  • ⚙️ Taşma hatası, tam sayı bölmesi, önbellek ve dal tahmini.

Alıştırmalar 🏋️

  1. Kâğıt-kalem: A E I K M O P R S T U dizisinde I ve Z için ikili aramanın iz tablosunu (lo, hi, mid) çıkarın.
  2. Kod laboratuvarında upper bound’u (key’den büyük ilk eleman) yazın. lower bound ile farkı nedir?
  3. “Bir sayının dizide kaç kez geçtiğini” lg N zamanda bulun. (İpucu: upper bound − lower bound.)
  4. p5.js’te bir loot sandığı yapın: ağırlıklar bir dizide, tıklayınca sandık açılsın ve çıkan eşya ekranda görünsün. 1000 kez açıp yüzdeleri yazdırın.
  5. Unity’de hızlı bir mermi (Rigidbody) duvara ateşleyin. Collision Detection: Discrete ↔ Continuous farkını gözlemleyin.
  6. 🤖 Bir YZ asistanından ikili arama yazmasını isteyin. Değişmezi kontrol edin; [7], [] ve tekrar eden elemanlarla test edin.

🎮 Bu sunumdaki oyunlar

Adı geçen oyunu tanımıyorsanız: oyuncuların kullandığı wiki sayfası ve oyunu kısaca gösteren bir video. ▶ video slaydın üstünde açılır (Esc ile kapanır); 🎯 işaretli bağlantılar doğrudan bu sunumdaki konuya gider.

Civilization 1991– · sıra tabanlı strateji
Bir uygarlığı taş devrinden uzay çağına yönetirsiniz; teknoloji ağacı serinin simgesi.

Kaynaklar: videolar 🎬

Kaynaklar: okuma ve görselleştirme 📚

NEXT LEVEL ▶
Temel Sıralama
İkili arama sıralı veri ister. Peki diziyi nasıl sıralarız?
SONRAKİ SUNUM ▶