Oyunun kuralları — sıralama nedir, neyi sayarız? rules of the game
Selection sort — en küçüğü seç seçmeli sıralama
Insertion sort — kart dizer gibi eklemeli sıralama
⭐ Yan görev: 2D oyunlarda çizim sırası
Shellsort — uzaktan atlayarak sırala
Arena — hangisi daha hızlı, neden?
Kararlılık — envanter ve skor tabloları stability
🎁 Bonus: karıştırma (Tetris, kart oyunları) shuffling
🎮 Bu dersin sonunda…
…“bu oyun neden takılıyor?”, “bu düşman listesini her karede sıralamalı mıyım?” gibi sorulara sayıyla cevap verebileceksiniz.
Oyun YZ dersinde neden sıralama?
🧭
A* yol bulma“En umut verici düğüm hangisi?” → sürekli sıralı tutulan bir liste
🎯
Hedef seçmeEn yakın / en zayıf düşmanı bul → “en küçüğü seç”
🧠
Utility AIHer eylemi puanla, en iyisini seç (veya ilk 3’ü)
🖼️
Çizim sırasıKim önde, kim arkada? Her karede sıralama
💥
Çarpışma tespitiFizik motorları nesneleri x’e göre sıralar
🃏
RastgelelikSunum karıştırma, Tetris torbası, loot
Algoritmalar = oyun YZ’sinin kas sistemi. Önce temel hareketleri öğreneceğiz. 💪
🤔 ISINMA SORUSU
Elinize karışık 7 iskambil kartı verildi. Onları nasıl sıralarsınız?
30 saniye düşünün. Yaptığınız şeyi adım adım tarif edebilir misiniz?
Çoğumuz şöyle yapar: soldan başlarız, her yeni kartı soldaki zaten sıralı kartların arasında doğru yere sokarız.
Tebrikler — az önce insertion sort yaptınız. 🎉
“Algoritma” kelimesi nereden geliyor?
Yıl ~820, Bağdat. Matematikçi el-Harezmî iki ünlü kitap yazar:
📘 1. kitap: Hint rakamlarıyla hesapBugün kullandığımız 0–9 rakamlarıyla toplama, çarpma, bölme nasıl yapılır? Adım adım anlatır.
📗 2. kitap: “el-Cebr”Denklem çözmeyi anlatır. Adı bugünkü cebir kelimesine dönüşür algebra.
Avrupalılar 1. kitabı Latinceye çevirirken yazarın adını “Algoritmi” diye yazar. Zamanla “Harezmî’nin yöntemi” = adım adım hesap yapma yolu anlamına gelir:
el-Harezmî→Algoritmi (Latince)→algorism→algoritma
📜 TanımAlgoritma: Bir problemi çözmek için adım adım izlenen, açık ve sonu olan talimatlar listesi. Yemek tarifi gibi — ama bilgisayar “göz kararı” anlamaz, her adım net olmalı.
Algoritma ve veri yapısı
⚙️ Algoritma algorithm
Veri üzerinde yapılan işlem: sırala, ara, en kısa yolu bul…
Mutfak benzetmesi: tarif
📦 Veri yapısı data structure
Verinin bellekte nasıl düzenlendiği: dizi, liste, yığın, ağaç…
Mutfak benzetmesi: dolabın düzeni
İkisi birbirinden ayrılmaz: dolap dağınıksa en iyi tarif bile yavaş kalır. Bugünkü veri yapımız en temel olanı: diziarray.
Programlar = Algoritmalar + Veri Yapıları
— Niklaus Wirth’in 1976 tarihli ünlü kitabının adı (Algorithms + Data Structures = Programs).
Mini sözlük (1/2)
sort / sorting
sıralama
Elemanları bir kurala göre (küçükten büyüğe vb.) dizmek
array
dizi
Bellekte yan yana duran, indeksle erişilen elemanlar: a[0], a[1], …
key
anahtar
Neye göre sıraladığımız: can puanı, mesafe, skor…
compare
karşılaştırma
“a[i], a[j]’den küçük mü?” sorusu
exchange / swap
yer değiştirme / takas
İki elemanın yerini değiştirmek
in-place
yerinde
Ek dizi kullanmadan, aynı dizi içinde sıralamak
inner / outer loop
iç / dış döngü
İç içe iki for — sıralamanın kalbi
Mini sözlük (2/2)
invariant
değişmez
Algoritma boyunca hep doğru kalan özellik (“solum hep sıralı”)
best / worst / average case
en iyi / en kötü / ortalama durum
Hangi girdide ne kadar sürer?
cost model
maliyet modeli
Hızı neyi sayarak ölçeceğimiz (biz: karşılaştırma ve yer değiştirme)
inversion
ters çift
Yanlış sırada duran eleman çifti
stable
kararlı
Eşit anahtarlıların eski sırası korunur
adaptive
uyarlanabilir
Girdi zaten “az bozuksa” daha hızlı çalışır
shuffle
karıştırma
Sıralamanın tersi: rastgele ama adil dizmek
LEVEL 0
Oyunun Kuralları
rules of the game
oyunun kuralları
selection sort
insertion sort
yan görev: çizim sırası
shellsort
arena: karşılaştırma
kararlılık
bonus: karıştırma
Sıralama problemi
Girdi: N elemanlı bir dizi
Çıktı: Aynı elemanlar, ama her eleman bir sonrakinden küçük ya da eşit:
\( a[0] \le a[1] \le \dots \le a[N-1] \)
Neyi sıraladığımız önemli değil — yeter ki iki elemanı karşılaştırabilelim.
🎮 Oyunda girdiler
Düşmanlar → mesafeye göre
Skor tablosu → puana göre
Envanter → nadirliğe göre
Sprite’lar → y koordinatına göre
A* düğümleri → f = g + h değerine göre
Kalın yazılanlar sıralama anahtarıkey.
🎒 Ön bilgi: sınıf ve nesne class & object
Sınıfclass = kalıp, plan. “Bir düşmanın adı ve canı olur.”
Hazır sıralama fonksiyonlarına nasıl karşılaştıracağını biz söyleriz. Başka bir fonksiyona verdiğimiz bu küçük fonksiyona geri çağırmacallback denir; burada görevi karşılaştırıcıcomparator olmak.
enemies.sort(key=lambda e: e.hp) # canı az olan önce
enemies.sort(key=lambda e: e.hp, reverse=True) # canı çok olan önce
leaderboard.sort(key=lambda p: (-p.score, p.time)) # önce puan, eşitse süre
enemies.Sort((x, y) => x.hp.CompareTo(y.hp)); // canı az olan önce
enemies.Sort((x, y) => y.hp.CompareTo(x.hp)); // canı çok olan önce
// CompareTo: negatif → x önce, 0 → eşit, pozitif → y önce
enemies.sort((x, y) => x.hp - y.hp); // canı az olan önce
enemies.sort((x, y) => y.hp - x.hp); // canı çok olan önce
Sıralama algoritması, anahtarın ne olduğunu bilmez; sadece “şu ikisinden hangisi önce?” diye sorar. Bu yüzden aynı algoritma her şeyi sıralayabilir.
🔗 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.
Karşılaştırıcı vermezseniz JavaScript elemanları metin olarak sıralar: "1" < "10" < "100" < "9" (sözlük sırası lexicographic order). Doğrusu: arr.sort((x, y) => x - y). Bu hata gerçek projelerde çok yaşanır!
Dizi bellekte nasıl durur? ⚙️
Dizi = bellekte yan yana duran, aynı boyutta kutular. Bu yüzden a[i]’nin adresi tek bir hesapla bulunur:
⚙️ Perde arkası: işaretçi pointer
Adres tutan değişkene işaretçi denir. C’de a[i] aslında *(a + i) demektir. C#’ta class nesneleri dizide referans (işaretçi) olarak durur; struct’lar ise doğrudan, yan yana.
Maliyet modeli: sadece iki işlem cost model
Kural: sıralama algoritmalarımız diziye sadece iki yardımcı fonksiyonla dokunur:
less(v, w)v, w’den küçük mü? → karşılaştırmacompare
exch(a, i, j)a[i] ile a[j]’yi takasla → yer değiştirmeexchange
Neden?
Sayabilmek için: Hız = kaç karşılaştırma + kaç yer değiştirme. Saniye bilgisayara göre değişir, bu sayılar değişmez.
Genellik için:less’i değiştirirsek aynı kod sayı, metin, düşman, sprite… her şeyi sıralar.
less ve exch kodu
def less(v, w):
return v < w
def exch(a, i, j):
a[i], a[j] = a[j], a[i] # Python'un "demet" (tuple) takası
🎒 C# sekmesindeki <T>: generic — “her tür için” yazılmış fonksiyon; where T : IComparable<T> = “T karşılaştırılabilir bir tür olmalı”. Şimdilik T yerine int düşünebilirsiniz.
Not: Canlı editörlerde görselleştirme için less(a, i, j) biçimini (değer yerine indeks) kullanacağız.
Takas neden üç adım? 🥤 swap
a bardağında kola, b bardağında ayran var. Yerlerini değiştirmek (takasswap) istiyoruz. Üçüncü boş bardak = geçici değişkentemporary variable, temp.
Quiz 2 · Takas
a = 5, b = 8. Şu iki satır çalışınca ne olur? a = b b = a
İlk satırda a’nın eski değeri (5) kaybolur. İkinci satırda b, a’nın yeni değerini (8) alır. Bu yüzden geçici değişken temp gerekir — ya da tek satırlık takas: Python a, b = b, a · C# (a, b) = (b, a); · JavaScript [a, b] = [b, a]; — üçü de arka planda geçici bir değer kullanır.
LEVEL 1
Selection Sort
Seçmeli sıralama — “En küçüğü bul, başa koy. Tekrarla.”
oyunun kuralları
selection sort
insertion sort
yan görev: çizim sırası
shellsort
arena: karşılaştırma
kararlılık
bonus: karıştırma
Fikir: en küçüğü seç selection sort
Dizinin tamamında en küçük elemanı bul.
Onu ilk elemanla takasla.
Kalan kısımda (2. elemandan itibaren) en küçüğü bul, ikinci elemanla takasla.
Dizi bitene kadar devam et.
Her turda kalanlar arasından en küçüğü seçiyoruz → adı buradan.
🏀 Gündelik hayattan
Beden dersinde boy sırasına girmek: Öğretmen önce sınıftaki en kısa kişiyi bulup en öne koyar, sonra kalanlardan en kısayı ikinci sıraya…
İz tablosu trace — S U P E R M A R I O
kırmızı = a[min] (bulunan en küçük) · siyah = en küçüğü bulmak için bakılanlar · gri = son yerine yerleşmiş
Selection sort — animasyon
karşılaştırılanşu anki en küçük (min)takaslananson yerinde
Selection sort — kod
def selection_sort(a):
n = len(a)
for i in range(n): # i: doldurulacak yer
min_i = i # şimdilik en küçük a[i]
for j in range(i + 1, n): # sağ tarafı tara
if a[j] < a[min_i]:
min_i = j # daha küçüğünü bulduk
a[i], a[min_i] = a[min_i], a[i] # takas (exch)
Değişmez invariant: neden doğru çalışıyor?
son yerinde (bir daha dokunulmaz)
henüz bakılmadı — ama hiçbiri soldakilerden küçük değil
↑ i
Her turun başında şu iki cümle hep doğrudur:
i’nin solundaki elemanlar sıralı ve son yerlerinde.
i’nin sağında soldakilerden küçük eleman yok.
Döngü bitince i = N → tüm dizi “solda” → sıralı. ✔ (Buna “doğruluk kanıtı” denir proof of correctness.)
💡 Neden önemli?Değişmez, kodu yazarken “bu döngü ne iş yapıyor?” sorusunun cevabıdır. YZ’ye kod yazdırdığınızda da kodun doğru olup olmadığını böyle kontrol edersiniz.
Kaç karşılaştırma? 📐 number of compares
Tur 0’da N−1, tur 1’de N−2, … son turda 0 karşılaştırma:
Önerme A
Selection sort, N elemanlı bir dizide ~N²/2 karşılaştırma ve N yer değiştirme yapar.
Kanıt (fikir)Soldaki tabloda her satır bir tur, her mavi kare bir karşılaştırma. Mavi kareler karenin yarısı kadar: ≈ N²/2. Her turda tam 1 takas var: N takas.
Küçük Gauss ve 1’den 100’e 📜
Anlatılan hikâyeye göre (biraz süslenmiş olabilir 😉): 1780’lerde bir öğretmen, sınıfı oyalamak için “1’den 100’e kadar sayıları toplayın” der.
Küçük Carl Friedrich Gauss birkaç saniyede cevabı yazar: 5050.
Selection sort’ta n = N−1 alırsak: \( \frac{(N-1)N}{2} \). Algoritma analizinde en çok karşılaşacağınız toplam bu!
Quiz 3 · Selection sort
Dizi zaten sıralıysa selection sort N = 1000 için yaklaşık kaç karşılaştırma yapar?
Selection sort girdiye kördür: “en küçük hangisi?” sorusunu cevaplamak için her turda kalanların hepsine bakmak zorunda. Sıralı, ters, rastgele fark etmez: 999·1000/2 = 499.500 karşılaştırma. (Animasyon slaytında “Sıralı” girdiyle deneyin!)
Selection sort’un karakteri
😴 Girdiye kör insensitive to input
Önceki turlardan hiçbir şey öğrenmez. Sıralı diziyi sıralamak, rastgele diziyi sıralamak kadar sürer.
🚚 En az veri hareketi minimal data movement
Tam olarak N takas — N’e göre doğrusal linear. Bildiğimiz hiçbir sıralama algoritması bundan azıyla yetinmez.
Peki az takas ne zaman önemli? → Takaslanan şey büyük ya da yazmak pahalıysa. (Birazdan: “perde arkası”)
🧪 Kod laboratuvarı: selection sort
Önce tahmin et, sonra çalıştır (Ctrl+Enter):
7. satırda less(a, j, min) yerine less(a, min, j) yaz.
6. satırda j = i + 1 yerine j = 0 yaz. Ne bozuldu?
7. satırı if (less(a, j, i)) exch(a, i, j); yap, 9. satırı sil. Hâlâ sıralıyor mu? Kaç takas?
🐍 Aynı laboratuvar — Python
Python tarayıcıda çalışır (Pyodide, ilk açılışta internet gerekir). print çıktısı sağ altta görünür.
print satırını kullanarak her turdan sonra dizinin halini izle. İz tablosuyla karşılaştır.
a[i], a[min_i] = a[min_i], a[i] ile kendin takasla — yazma (write) sayacı ne gösteriyor?
⚙️ Takas ettiğimiz şey ne kadar büyük?
C#’ta (Unity) iki tür nesne vardır:
struct (değer tipi value type): dizide verinin kendisi durur. Takas = tüm baytları kopyalamak.
class (referans tipi reference type): dizide sadece adres (8 bayt) durur. Takas = 2 adresi kopyalamak.
200 baytlık bir struct EnemyData dizisini sıralarken her takas ~400 bayt taşır. Selection sort’un “sadece N takas” özelliği burada parlar. ✨
⚙️ Profesyonel numara: indeksleri sırala indirect sort
Büyük verileri yerinden oynatma! Onun yerine int[] order = {0,1,2,…} gibi küçük bir indeks dizisini sırala; karşılaştırırken data[order[i]]’ye bak.
Aynı fikir: flash bellek/EEPROM (yazma ömrü sınırlı), robot kolu ile kutu taşımak, ağ üzerinden veri…
🎮 İç döngü = en yakın düşmanı bulmak
Haritaya tıklayarak büyücüyü taşıyın. Selection sort’un tek bir turu = “en yakın düşman”. K tur = “en yakın K düşman”.
🧠 Utility AIHer eylem (saldır, kaç, iyileş) bir puan alır; NPC en yüksek puanlıyı seçer → tek tur, N karşılaştırma.
⚙️ sqrMagnitude neden?Mesafeleri karşılaştırırken karekök almaya gerek yok: a < b ⇔ a² < b². Karekök pahalı bir işlemdir — her karede yüzlerce kez yapılıyorsa fark eder.
🎒 Önceki koddaki yeni ifadeler
for e in enemies
listeyi gez
“enemies listesindeki her e için…” — Python for … in, C# foreach (var e in …), JS for (const e of …)
float('inf') · float.MaxValue · Infinity
“sonsuz”
En küçüğü ararken başlangıç değeri: ilk bakılan her mesafe bundan küçük çıkar
best = None / null
“henüz yok”
Hiçbir nesneyi göstermeyen değişken. Liste boşsa fonksiyon None/null döndürür
e.transform.position
Unity: konum
Nesnenin sahnedeki konumu: bir Vector3 (x, y, z)
(a - b).sqrMagnitude
Unity: mesafe²
İki konum arasındaki vektörün uzunluğunun karesi (karekök yok → hızlı)
List<Enemy>
C#: liste
Sadece Enemy nesneleri tutabilen liste. <> içindeki tür = elemanların türü
Dansçıların sırtındaki numaralar dizi elemanları. Şapkalı dansçı = min işaretçisi.
🤔 İzlerken sayKaç kez takas oldu? Önerme A ile uyuşuyor mu?
LEVEL 2
Insertion Sort
Eklemeli sıralama — “Sıradakini al, solundaki sıralı kısımda yerine sok.”
oyunun kuralları
selection sort
insertion sort
yan görev: çizim sırası
shellsort
arena: karşılaştırma
kararlılık
bonus: karıştırma
Fikir: kart dizer gibi insertion sort
İz tablosu — S U P E R M A R I O
kırmızı = a[j] (yeni eklenen, yerine oturdu) · siyah = bir sağa kaydırılanlar · gri = yerinden oynamayanlar
Insertion sort — animasyon
karşılaştırılantakaslanansıralı ama son yerinde olmayabilirbitti
Insertion sort — kod
def insertion_sort(a):
for i in range(1, len(a)): # a[i]'yi solundakilere ekle
j = i
while j > 0 and a[j] < a[j - 1]: # solundaki daha büyükse…
a[j], a[j - 1] = a[j - 1], a[j] # …takasla, bir sola geç
j -= 1
Dikkat: iç döngü, solundaki eleman küçük çıktığı anda durur. Bütün sihir bu erken durmada. ✨
Değişmez invariant
sıralı (ama son yerinde olmayabilir)
henüz bakılmadı
↑ i
i’nin solundaki elemanlar kendi aralarında sıralı.
i’nin sağındaki elemanlara hiç bakılmadı.
SelectionSol taraf son halinde. Sağa bakmadan bitemez.
InsertionSol taraf geçici. Ama sağa hiç bakmadığı için yeni gelen elemanları da sıralayabilir → çevrimiçi online algoritma.
Kaç karşılaştırma? Girdiye bağlı!
Önerme B
Rastgele sıralı, anahtarları farklı N elemanlı bir dizide insertion sort ortalama ~N²/4 karşılaştırma ve ~N²/4 takas yapar.
En kötü durumda (ters sıralı) ~N²/2 ve ~N²/2; en iyi durumda (sıralı) N−1 karşılaştırma ve 0 takas.
Ortalama neden N²/4? Rastgele dizide yeni eleman, sıralı kısmın ortalama yarısı kadar sola yürür: en kötünün (N²/2) yarısı.
Ters çift inversion 🔁
Ters çift: dizide yanlış sırada duran her (soldaki, sağdaki) çift. Örn. E A bir ters çifttir.
Insertion sort’un gizli gücü
Önerme C
Insertion sort’un takas sayısı = dizideki ters çift sayısı. Karşılaştırma sayısı: en az ters çift sayısı, en fazla ters çift sayısı + (N − 1).
Kısmen sıralıpartially sorted dizi: ters çift sayısı N ile orantılı (az) olan dizi. Örnekler:
Her eleman, son yerine yakın (kareden kareye biraz kayan sprite’lar 👀)
Büyük sıralı diziye birkaç yeni eleman eklenmiş (yeni skorlar)
Sadece birkaç eleman yanlış yerde
Kısmen sıralı dizide insertion sort ≈ doğrusal (N) zamanda çalışır!
Quiz 4 · Ters çiftler
Hangisinde insertion sort daha az takas yapar ve kaç takas? X = [1, 2, 3, 5, 4, 6, 7, 8]Y = [8, 7, 6, 5, 4, 3, 2, 1]
X’te tek ters çift var: (5, 4). Y’de her çift ters: 8·7/2 = 28. Selection sort ise ikisinde de 8·7/2 = 28 karşılaştırma yapardı — girdiye kör!
🧪 Kod laboratuvarı: insertion sort
Tahmin et → değiştir → çalıştır:
4. satırda j > 0 yerine j >= 0 yaz. Hata mesajı ne diyor, neden?
&& less(…) kısmını döngüden çıkar, içeriye if (less(a, j, j - 1)) exch(a, j, j - 1); yaz. Girdi = Sıralı iken karşılaştırma sayısı?
less(a, j, j - 1) yerine !less(a, j - 1, j) (yani ≤) yaz. Girdi = Az farklı değer. Takas sayısı ne oldu?
İyileştirme: takas yerine kaydır half exchanges
Kartı elimize alıyoruz, büyük kartları bir sağa kaydırıyoruz, kartı açılan boşluğa koyuyoruz.
Takas = 3 atama. Kaydırma = 1 atama. → Dizi erişimi yaklaşık yarıya iner.
🧪 DeneBu sürümü JavaScript laboratuvarına yaz (a[j] = a[j - 1] atamalarını da görselleştirir). “yazma” sayacına bak!
N² bir algoritma… dünyanın en hızlı kütüphanelerinde? 🤯
Kütüphane
Ana algoritma
Küçük parçalar için
Python list.sort()
Timsort
(ikili) insertion sort — ~32–64 elemanlık parçalar
C# Array.Sort (.NET)
Introsort (quicksort + heapsort)
insertion sort — ≤ 16 eleman
Chrome V8 (2018 öncesi)
Quicksort
insertion sort — ≤ 10 eleman
C++ std::sort (yaygın uygulamalar)
Introsort
insertion sort — ~16 eleman
Neden? Küçük N’de N² ile N log N arasındaki fark önemsiz; insertion sort’un ek yükü yok, kodu minicik ve belleğe komşu komşu erişiyor → CPU önbelleği çok sever.
Ders: “Büyük-O” her şey değildir. Sabitler ve donanım da önemli. → Sonraki slayt.
⚙️ Bellek hiyerarşisi: her “okuma” eşit değil memory hierarchy
Klasik “her programcının bilmesi gereken gecikmeler” (Jeff Dean / Peter Norvig). İnsan ölçeği: 1 ns = 1 saniye olsaydı…
L1 önbellek okuma
0,5 ns
yarım saniye — göz kırpmak
L2 önbellek okuma
7 ns
7 saniye — bir yudum çay
Ana bellek (RAM)
100 ns
1,5 dakika — çay demlemek
SSD’den rastgele okuma
~150 µs
~2 gün
Hard diskte arama
10 ms
~4 ay
Paket: Kaliforniya → Hollanda → geri
150 ms
~5 yıl
CPU, RAM’den tek bayt istemez: 64 baytlık bir bloğu (önbellek satırı cache line) birden getirir. Komşu elemanlar “bedavaya” gelir.
⚙️ Önbellek cache simülasyonu: dizi vs bağlı liste linked list
Her hücre bir bellek adresi, her satır (8 hücre) bir önbellek satırı. Önbellek sadece 3 satır tutabiliyor. Dizi elemanları yan yana; bağlı liste düğümleri belleğe dağılmış (her düğüm bir sonrakinin adresini tutar).
📜 Stack Overflow’un en ünlü sorusu
“Neden sıralı bir diziyi işlemek, sıralı olmayanı işlemekten daha hızlı?” (2012)
Aynı C++ kodu, data önceden sıralanınca ~6 kat hızlandı!
⚙️ Dal tahmini branch prediction
CPU, if’in sonucunu beklemeden tahmin edip devam eder. Sıralı veride tahmin hep tutar (önce hep “hayır”, sonra hep “evet”). Rastgele veride %50 yanılır ve her yanılgıda boru hattını pipeline boşaltır.
Ünlü cevaptaki benzetme: tren makasçısı, trenin hangi yöne gideceğini tahmin edip makası önceden çevirir.
Bir dansçı öne çıkar ve kendinden büyük olanları geçerek sola doğru “dans eder” → iç döngü.
🤔 KarşılaştırSelection dansıyla karşılaştırın: Hangisinde dansçılar daha çok yer değiştiriyor? Hangisinde daha çok “bakışma” (karşılaştırma) var?
⭐ SIDE QUEST
Kim Önde Çizilir?
2D oyunlarda çizim sırası — insertion sort’un oyundaki süper gücü
oyunun kuralları
selection sort
insertion sort
yan görev: çizim sırası
shellsort
arena: karşılaştırma
kararlılık
bonus: karıştırma
Ressam algoritması painter’s algorithm
Tepeden bakışlı (top-down) 2D oyunlar (Stardew Valley, Zelda benzeri…): ekranın altına yakın olan nesne kameraya daha yakındır → önde çizilmeli.
Ressam gibi çiziyoruz: önce uzaktakiler (y’si büyük), sonra yakındakiler üstüne.
→ Her karede nesneleri y’ye göre sırala, sırayla çiz.
Saniyede 60 kare × yüzlerce nesne. Hangi sıralama algoritması? 🤔
🎨 Aynı fikir 3D’de
Yarı saydam nesneler (cam, duman, parçacık) derinlik tamponuyla doğru çizilemez; motorlar onları kameraya uzaklığa göre arkadan öne sıralayıp çizer.
🎮 Canlı demo: y-sıralama
🤔 TARTIŞMA
Demoda “önceki karenin sırası” ile insertion sort neden bu kadar ucuz?
Karakterler çok hızlı hareket ederse ne olur?
Oyunun ilk karesinde ne olur? Ya bir sahne geçişinde (ışınlanma)?
Ağaçlar hiç hareket etmiyor. Bunu nasıl kullanabiliriz?
Zamansal tutarlılık temporal coherence
Oyun dünyası kareden kareye çok az değişir. Önceki karenin cevabı, bu karenin cevabına çok yakındır.
💥 Sweep and Prune (fizik motorları)
Çarpışma adayı çiftleri bulmak için her nesnenin kutusu x eksenine izdüşürülür ve uç noktalar sıralanır. Sadece aralıkları çakışan çiftler detaylı kontrol edilir.
Uç noktalar her karede biraz kayar → insertion sort ile güncellenir (ör. Bullet fizik motorundaki “axis sweep” yaklaşımı).
Kodda y-sıralama: Unity · pygame · p5.js
Not: Gerçek projede Unity bunu sizin için yapabilir (2D: Transparency Sort Axis = (0, 1, 0); Godot: Y Sort). Ama arkasındaki fikir tam olarak bu.
🎒 Önceki koddaki yeni ifadeler
: MonoBehaviour
Unity
“Bu sınıf bir Unity bileşenidir” — nesneye eklenebilir, Update/LateUpdate gibi metotları Unity çağırır
LateUpdate()
Unity
Her karede, tüm Update’lerden sonra çağrılır (herkes hareket etti → şimdi sırala)
static readonly
C#
static: tüm nesneler için tek kopya · readonly: bir kez atanır, değişmez
Comparison<T>
C#
“İki T alıp int döndüren fonksiyon” türü. Lambda’yı bir değişkende saklamamızı sağlar
InsertionSort<T>(…)
C# generic
Her tür liste için çalışan tek fonksiyon (T = “herhangi bir tür”)
sortingOrder
Unity
SpriteRenderer’ın çizim sırası: büyük sayı önde çizilir
screen.blit / rect.bottom
pygame
Resmi ekrana çiz / sprite’ın alt kenarının y’si (ayaklar)
draw()
p5.js
p5.js her karede (saniyede ~60 kez) kendiliğinden çağırır
⚙️ Çöp toplayıcı garbage collector ve takılan oyunlar
C#, Python, JavaScript’te yeni nesneler oluşturursunuz; kullanılmayanları çöp toplayıcı (GC) arada bir temizler.
Belediye çöp kamyonu gibi: geldiğinde sokak birkaç saniye durur. Oyunda bu, ekranın bir anlığına donması demek GC spike / stutter.
60 FPS’te bir karenin süresi: 16,6 ms. 5 ms’lik bir GC duraklaması o karenin üçte birini yer.
🎒 OrderBy(e => e.dist): C# LINQ, sıralanmış yeni bir dizi üretir · sorted(...): Python, yeni liste döndürür (.sort() ise yerinde sıralar) · [...enemies]: JS “yayma” spread ile dizinin kopyası.
LEVEL 3
Shellsort
Önce uzaktan kaba ayar, sonra yakından ince ayar
oyunun kuralları
selection sort
insertion sort
yan görev: çizim sırası
shellsort
arena: karşılaştırma
kararlılık
bonus: karıştırma
Insertion sort’un zayıf noktası 🐌
En küçük eleman dizinin en sonundaysa, ona yer açmak için herkes teker teker kayar: N−1 takas, hep birer adım.
Fikir: Elemanlar uzak mesafelere tek hamlede atlayabilseydi? 🦘
h-sıralı dizi h-sorted array
Aralarında h adım olan elemanlar (her renk bir grup) kendi aralarında sıralıysa dizi h-sıralıdır.
Shellsort fikri
Büyük bir h seç; diziyi h-sırala (her grup için insertion sort, h adımlı atlayarak).
h’yi küçült, tekrarla.
Son olarak h = 1: normal insertion sort.
Neden hızlı?
Büyük h: gruplar kısa → ucuz. Elemanlar uzağa atlar.
Küçük h: dizi artık kısmen sıralı → insertion sort’un sevdiği durum!
📜 Adı nereden geliyor?
Türkçe kaynaklarda bazen “kabuk sıralaması” denir — ama kabukla ilgisi yok! 🐚 Algoritmayı 1959’da yayımlayan Donald L. Shell’in soyadı.
🎬 Ara: 15 sıralama algoritması, sesli
15 Sorting Algorithms in 6 Minutes Timo Bingmann · 5 dk 50 sn · YouTube’da aç
Her algoritma aynı rastgele diziyi sıralıyor; çubuklar değerler, ses yüksekliği karşılaştırılan değer. Selection, insertion ve shellsort’un “sesini” birbirinden ayırt etmeye çalışın.
🤔 İzlerkenHangi algoritma en uzun sürdü, hangisi en kısa? Insertion sort’un sonlara doğru neden yavaşladığını sesten duyabiliyor musunuz? Shellsort’un ilk turları ne yapıyor?
Alttaki renkli şerit: aynı renk = aynı h-grubu. h dizisini değiştirip karşılaştırma sayısını izleyin.
Shellsort — kod
def shell_sort(a):
n = len(a)
h = 1
while h < n // 3:
h = 3 * h + 1 # 1, 4, 13, 40, 121, ...
while h >= 1:
for i in range(h, n): # h adımlı insertion sort
j = i
while j >= h and a[j] < a[j - h]:
a[j], a[j - h] = a[j - h], a[j]
j -= h
h //= 3 # bir sonraki (daha küçük) h
# h = 1 turu bittiğinde dizi sıralı
Insertion sort’tan farkı: 1 yerine h yazmak + dışarıda bir döngü. Sadece birkaç satır! 😮
Shellsort ne kadar hızlı? 📐
Önerme D
3x+1 dizisiyle Shellsort, en kötü durumda \( O(N^{3/2}) \) karşılaştırma yapar.
N
N²/2 (selection)
N3/2 (shellsort, en kötü)
oran
1.000
500.000
31.623
~16×
1.000.000
500 milyar
1 milyar
~500×
📜 60 yıllık bilmece
Shellsort’un ortalama performansının tam formülü hâlâ bilinmiyor! En iyi h dizisi de bilinmiyor. Basit görünen bir algoritma, matematikçiler için hâlâ açık bir problem.
Gerçek hayatta: kodu çok kısa ve ek bellek istemediği için gömülü sistemlerde (ör. uClibc’nin qsort’u) ve bzip2 sıkıştırma programında kullanıldı.
Quiz 5 · Shellsort
h dizisi sadece [1] olursa Shellsort neye dönüşür? Son h neden 1 olmak zorunda?
h = 1 turu, düz insertion sort’tur. Örneğin son h = 2 olsaydı dizi sadece “2-sıralı” olurdu: [1, 0, 3, 2] 2-sıralıdır ama sıralı değildir!
🧪 Kod laboratuvarı: shellsort
Deneyler (N = 80, Rastgele): karşılaştırma sayısını not et, sonra:
4. satırı while (h * 2 < n) h = h * 2;, 11. satırı h = Math.floor(h / 2); yap (2’nin kuvvetleri). Daha mı iyi?
5. satırda h >= 1 yerine h > 1 yaz. Ne oldu?
4. satırı silip sadece h = 1 bırak. Karşılaştırma sayısı = insertion sort’unki mi?
Dansçılar önce uzaktaki partnerleriyle eşleşir (büyük h), sonra giderek yakındakilerle (h küçülür).
🤔 İzlerkenVideoda hangi h değerleri kullanılıyor? Son turda kaç takas oluyor — neden bu kadar az?
LEVEL 4
Arena
Üç algoritma, aynı dizi. Kim kazanır?
oyunun kuralları
selection sort
insertion sort
yan görev: çizim sırası
shellsort
arena: karşılaştırma
kararlılık
bonus: karıştırma
🏁 Yarış! Önce tahmin edin
N büyüdükçe ne olur? 📈 order of growth
Fareyi grafiğin üzerinde gezdirin. Süreler, saniyede 1 milyar karşılaştırma yapan hayali bir bilgisayar için.
Küçük terimleri neden atıyoruz? tilde notation
\( \dfrac{N(N-1)}{2} = \dfrac{N^2}{2} - \dfrac{N}{2} \) → büyük N için \( \sim \dfrac{N^2}{2} \) yazarız. “~” = “yaklaşık, baskın terim”.
Büyük-O ile ilişkisi Big-O
Tilde (~) gösterimi kullanılır çünkü sabiti korur (N²/2 ile N²/4 farklıdır). Büyük-O sabiti de atar: ikisi de \( O(N^2) \). İş görüşmelerinde Büyük-O sorulur; ikisini de tanıyın.
🧪 Bilimsel yöntem: iki katına çıkarma deneyi doubling test
Formül tahminimiz doğru mu? Ölçelim!
N’i iki katına çıkar, süre kaç katına çıkıyor?
Süre ~ N² ise → oran ≈ 2² = 4
Süre ~ N1.5 ise → oran ≈ 21.5 ≈ 2,8
Süre ~ N ise → oran ≈ 2
Genel kural: \( b = \log_2(\text{oran}) \) → süre \( \sim N^b \)
Kabarcık sıralamasıbubble sort: komşuları karşılaştır, yanlışsa takasla; büyükler “kabarcık gibi” sona yükselir. En çok bilinen sıralama… ama en kötülerinden biri.
🎤 2007, Google
CEO Eric Schmidt, başkan adayı Barack Obama’ya şaka yollu sorar: “Bir milyon 32-bitlik tamsayıyı sıralamanın en verimli yolu nedir?”
Obama: “I think the bubble sort would be the wrong way to go.” 😄
Donald Knuth: “Bubble sort’un, akılda kalıcı bir adı olması dışında önerilecek hiçbir yanı yok gibi görünüyor.”
Bir sıralama, anahtarı eşitequal keys olan elemanların önceki göreli sırasını koruyorsa kararlıdır.
🏆 Skor tablosu
İki oyuncu 900 puan aldı. Kural: “Eşitlikte önce bitiren önde.”
Çözüm: Önce bitirme zamanına göre sırala, sonra puana göre kararlı sırala. Puanı eşit olanlar zaman sırasını korur!
oyuncu
puan
bitirme
Ayşe
950
4:12
Mert
900
3:58
Zeynep
900
4:30
Can
720
3:10
Kararsız bir algoritma Zeynep’i Mert’in önüne koyabilir — oyuncular forumda isyan eder. 😤
🎮 Envanter: “İsme göre”, sonra “Nadirliğe göre”
Selection sort neden kararsız?
Anahtar = harf. Alt indis sadece “kimin önce geldiğini” takip etmek için: B₁ B₂ A
başlangıç
B₁
B₂
A
i=0: min = A → a[0] ile takas
A
B₂
B₁
sonuç
A
B₂
B₁
Uzak mesafeli takas, B₁’i B₂’nin üzerinden atlattı. Insertion sort sadece komşu takası yapar ve eşitleri asla takaslamaz (< kullanır, ≤ değil) → kararlı.
Quiz 6 · Kararlılık
Hangileri kararlıdır?
Selection: uzak takas → kararsız. Shellsort: h adımlı atlamalar eşitlerin sırasını bozabilir → kararsız. Insertion: sadece komşu takası, eşitleri takaslamaz → kararlı. (Laboratuvarda < yerine ≤ kullanırsanız insertion da kararsızlaşır!)
Kullandığınız dil kararlı mı sıralıyor? ⚠️
Dil / fonksiyon
kararlı?
not
Python sorted(), list.sort()
✔
Timsort — garanti
JavaScript Array.prototype.sort
✔
ES2019’dan beri garanti
C# LINQ OrderBy / ThenBy
✔
kararlı ama yeni koleksiyon üretir (GC!)
C# Array.Sort, List<T>.Sort
✘
introsort — eşitlerin sırası garanti değil
🐞 Unity’de klasik hataList.Sort ile puana göre sıralanan skor tablosunda eşit puanlılar her yenilemede yer değiştirip titreyebilir. Çözüm: karşılaştırıcıya ikinci anahtar ekleyin (score eşitse time’a bak) ya da kararlı bir sıralama kullanın.
🎁 BONUS LEVEL
Karıştırma
shuffling — sıralamanın tersi: rastgele ama adil
oyunun kuralları
selection sort
insertion sort
yan görev: çizim sırası
shellsort
arena: karşılaştırma
kararlılık
bonus: karıştırma
Knuth karıştırması Fisher–Yates / Knuth shuffle
Adiluniform karıştırma: her sıralanış (permütasyon permutation) eşit olasılıkla çıkmalı.
Fikir: soldan sağa git; i. adımda 0…i arasından rastgele birini seç, a[i] ile takasla.
Tek tur, N takas → doğrusal zaman. Selection sort’un “rastgele” kardeşi gibi!
1938’de Fisher & Yates kâğıt-kalemle; 1964’te Durstenfeld bilgisayar için; Knuth “The Art of Computer Programming” ile yaydı.
import random
def shuffle(a):
for i in range(len(a)):
r = random.randint(0, i) # 0..i (i dahil!)
a[i], a[r] = a[r], a[i]
🎒 Rastgele sayılar: Python random.randint(0, i) → 0…i (i dahil) · C# rng.Next(i + 1) → 0…i (üst sınır hariç) · JS Math.random() → 0 ≤ x < 1 ondalıklı sayı, bu yüzden Math.floor(Math.random() * (i + 1)) → 0…i.
🎲 Deney: hangi karıştırma adil?
Her çubuk bir permütasyonun kaç kez çıktığını gösterir. Adil karıştırmada hepsi kesikli “beklenen” çizgisine yakın olmalı. Çubukların üzerine gelince sayıyı görürsünüz.
📜 Karıştırma hatalarının gerçek bedeli
🃏 1999 — Çevrimiçi poker
Bir poker yazılımı karıştırma algoritmasını “güvenilirlik” için web sitesinde yayınladı. Güvenlik araştırmacıları iki hata buldu: (1) yukarıdaki saf yöntem, (2) rastgele sayı üreteci random number generator, RNG gece yarısından beri geçen milisaniye ile başlatılıyordu (tohumseed).
Sonuç: kendi 5 kartlarını görüp sunucu saatiyle eşleştirerek herkesin kartlarını gerçek zamanlı hesapladılar.
🗳️ 2010 — Tarayıcı seçim ekranı
AB kararıyla Windows kullanıcılarına 5 tarayıcıyı rastgele sırada gösteren bir ekran sunuldu. Kod: sort(() => 0.5 - Math.random()).
Analizler sıralamanın adil olmadığını gösterdi: bazı tarayıcılar belirli konumlarda çok daha sık çıkıyordu. Kod sonradan Fisher–Yates ile düzeltildi.
Kaynaklar: “How We Learned to Cheat at Online Poker” (Arkin ve ark., 1999); Rob Weir, “Doing the Microsoft Shuffle” (2010).
🎮 Tetris’in “7-torba” sistemi 7-bag randomizer
Her parça zar atar gibi rastgele seçilirse uzun çubuk (“I”) onlarca parça boyunca gelmeyebilir 😩. Modern Tetris oyunları 7 parçayı bir torbaya koyar, torbayı karıştırır ve sırayla dağıtır; torba bitince yenisini karıştırır. Böylece iki “I” arasında en fazla 12 parça olur.
shuffle önceki slayttaki Knuth (Fisher–Yates) karıştırmasıdır. Soldaki alt sırada her boşluk yeni bir torbanın başladığı yerdir.
Quiz 7 · Karıştırma
arr.sort(() => Math.random() - 0.5) neden kötü bir karıştırmadır?
Sıralama algoritmaları karşılaştırıcının tutarlı olduğunu varsayar (a<b ve b<c ise a<c). Rastgele cevaplar bu varsayımı bozar; bazı permütasyonlar daha olası hale gelir (deneyde gördünüz). Ayrıca N log N, Fisher–Yates’in N’inden yavaştır.
STAGE CLEAR ✔
Oyun YZ’sine Köprü
Bugün öğrendiklerimiz önümüzdeki haftalarda nerede karşımıza çıkacak?
A* yol bulmaya bir bakış 🧭
A*, her adımda f değeri en küçük düğümü seçer (selection sort’un iç döngüsü!).
Listeyi sıralı tutmak için her yeni düğümü yerine sokarız (insertion sort’un bir adımı).
🤔 Ama…Her ekleme O(N). Binlerce düğümde yavaşlar. Daha iyisi: öncelik kuyruğupriority queue / binary heap → ekleme ve çıkarma O(log N). Yakında!
Derin hikâye: Hollerith’in delikli kartları ve 1890 nüfus sayımı
ABD’nin 1880 nüfus sayımının elle işlenmesi yaklaşık 8 yıl sürdü. Nüfus hızla büyüyordu; 1890 sayımı bir sonraki sayıma yetişmeyebilirdi.
Herman Hollerith’in çözümü: her kişi için bir delikli kart ve kartları elektrikle okuyup sayan makineler. 1890 sayımının sonuçları çok daha kısa sürede çıktı.
Sonraki kart sıralama makineleri bir kolondaki rakama göre kartları 10 cebe dağıtıyordu. Operatör cepleri sırayla toplayıp bir sonraki kolon için tekrar ediyordu: en anlamsız haneden başlayan taban (radix) sıralaması, karşılaştırma yapmadan sıralama.
Hollerith’in 1896’da kurduğu şirket birleşmelerle 1924’te adını IBM olarak değiştirdi.
DersSıralama, bilgisayardan önce de bir mühendislik problemiydi. Radix sıralaması karşılaştırma yapmadığı için N log N alt sınırına takılmaz (Mergesort sunumundaki alt sınır sadece karşılaştırmalı sıralamalar içindir). Obama’nın 2007’deki ünlü cevabındaki soru (“bir milyon 32 bitlik tamsayıyı en iyi nasıl sıralarsın?”) için de beklenen cevap buydu.
Çizim sırası: saydam nesneler kameraya uzaklığa göre arkadan öne sıralanır (Unity bunu kendisi yapar; 2D’de Sorting Layer/Order).
Liderlik tablosu: puan, sonra süre, sonra isim: çok anahtarlı ve kararlı sıralama.
Neredeyse sıralı veri: her kare az değişen bir liste (ör. mesafeye göre düşmanlar) için ekleme sıralaması çoğu zaman en hızlısıdır.
En iyi k tanesi lazımsa bütün listeyi sıralamayın: kısmi seçim ya da yığın (Öncelik Kuyrukları).
Rastgele karşılaştırıcı tuzağılist.sort(() => Math.random() - 0.5) ile “karıştırmak” yanlıdır: sıralama algoritması tutarlı bir karşılaştırıcı varsayar. 2010’da AB için hazırlanan tarayıcı seçim ekranındaki karıştırma kodunun bu yüzden bazı tarayıcıları belirgin şekilde daha sık belli konumlara koyduğu gösterildi. Doğrusu: Fisher–Yates karıştırması.
“Unity 6, C#. Bir liderlik tablosu yaz: kayıtlar (isim, puan, süre). Sıralama: puan azalan, eşitse süre artan, eşitse isim (kültürden bağımsız, ordinal). Her karede değil, sadece yeni skor gelince güncelle; yeni skoru ikili aramayla doğru yere ekle. Ayrıca Fisher–Yates ile tohumlu karıştırma fonksiyonu ve her ikisi için NUnit testleri ekle.”
Kararlılık gerekip gerekmediğini açıkça yazın
Sayısal karşılaştırıcıyı (JS) isteyin
Her karede sıralama yerine artımlı güncelleme sorun
Karıştırma için Fisher–Yates isteyin
🚀 Proje ve araştırma önerileri
[kolay]Sıralama görselleştirici — p5.js’te dört temel sıralamayı aynı veriyle yarıştırın; karşılaştırma ve takas sayısını gösterin.
[kolay]Liderlik tablosu — Çok anahtarlı, kararlı sıralama + ikili aramayla ekleme.
[orta]Neredeyse sıralı veri — Her kare biraz karışan 1.000 düşman listesinde ekleme sıralaması ile Array.Sort’u ölçün.
[araştırma]Yanlı karıştırma — Rastgele karşılaştırıcıyla 1 milyon karıştırma yapıp her elemanın konum dağılımını çizin; Fisher–Yates ile karşılaştırın.
Selection: ~N²/2 karşılaştırma, girdiye kör; ama sadece N takas.
Insertion: ters çift kadar takas; neredeyse sıralı veride ≈ N. Küçük dizilerin kralı.
Shellsort: uzaktan h-sıralama + insertion → N3/2.
~ notasyonu ve iki katına çıkarma deneyi.
Kararlılık: çok anahtarlı sıralama için şart.
Fisher–Yates: adil karıştırmanın tek doğru yolu.
⚙️ önbellek, işaretçi, dal tahmini, GC: donanım da önemli.
🎮 Oyunlar: en yakın hedef, y-sıralama, envanter, Tetris torbası.
Alıştırmalar 🏋️
Bubble sort’u son slayttaki laboratuvarda yazın, erken çıkış (swapped) ekleyin. Sıralı / ters / rastgele girdide insertion sort ile karşılaştırın.
p5.js’te y-sıralama yapan küçük bir sahne yazın (ağaçlar + hareket eden karakter). Her karede kaç karşılaştırma yaptığınızı ekrana yazdırın.
Unity’de 10 oyunculu bir skor tablosu: puan eşitse önce bitiren önde. Hem List.Sort + ikinci anahtar, hem kararlı insertion sort ile yapın.
Kağıt-kalem: E A S Y Q U E S T I O N dizisi için selection ve insertion sort’un iz tablosunu çıkarın. Kaç ters çift var?
🤖 Bir YZ asistanından “C#’ta insertion sort” isteyin. Kodun değişmezini bulun ve doğru olduğunu kendi cümlelerinizle açıklayın.
🧪 Serbest laboratuvar
Fikirler: erken çıkış ekle · çift yönlü bubble (cocktail sort) · “gnome sort” · ters çift sayan fonksiyon yaz ve print ile yazdır.
🐍 Serbest laboratuvar — Python
İpucu: v = a[i] ile elemanı al, büyükleri a[j] = a[j - 1] ile kaydır, sonra a[j] = v. Yazma sayısını takaslı sürümle karşılaştır.
🎮 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.
Tetris1984 · bulmaca
Düşen dörtlü blokları satır tamamlayacak biçimde yerleştirirsiniz; modern sürümler “7-torba” ile karıştırır.