🧩 3.4: Queue Algoritmaları ve Simülasyonlar

Gerçek Hayat Problemleri ve Çözümleri

📚 Queue Kullanım Alanları

🎮

Oyun Geliştirme

Oyuncu hareketleri, input buffer, event sistemi

🌐

Web Sunucuları

HTTP istek kuyruğu, load balancing

📱

Mesajlaşma

Message queue, async işlemler

🔄

Task Scheduling

CPU process scheduling, cron jobs

1. Sıcak Patates Oyunu (Josephus Problemi)

🥔 Sıcak Patates Nedir?

Çocuk oyunu: Herkes daire şeklinde oturur, bir patates (veya top) elden ele geçirilir. Müzik durduğunda elinde patates kalan oyundan çıkar!

📜 Tarihsel Arka Plan: Josephus Problemi

MS 67, Yahudi-Roma Savaşı: Tarihçi Josephus ve 40 asker Romalılar tarafından kuşatıldı. Teslim olmak yerine intihar etmeye karar verdiler. Daire şeklinde durup her 3. kişi öldürülecekti. Josephus matematik kullanarak kendini ve arkadaşını son iki kişi olarak konumlandırdı ve hayatta kaldılar!

🔄 Queue ile Nasıl Çözülür?

  1. Başlangıç: Tüm oyuncuları queue'ya ekle
  2. Her turda: k kez dequeue yap ve hemen enqueue yap (elden ele geçir)
  3. Eleme: k. kişiyi dequeue yap ama geri ekleme (elendi!)
  4. Tekrar: Tek kişi kalana kadar devam et

🎮 İnteraktif Josephus Simülasyonu

📊 Durum:
Başlamak için ▶️ tıklayın
🔢 Queue Durumu:
[Ali, Veli, Ayşe, Fatma, Can, Zeynep]
❌ Elenenler:
-
Python Kodu
from collections import deque

def sicak_patates(oyuncular, tur_sayisi):
    q = deque(oyuncular)
    print(f"Başlangıç: {list(q)}\n")
    
    tur = 1
    while len(q) > 1:
        # Patatesi elden ele geçir
        for i in range(tur_sayisi):
            kisi = q.popleft()
            q.append(kisi)
            
        # Tur bitti, elinde patates olan yandı
        yanan = q.popleft()
        print(f"Tur {tur}: {yanan} yandı! Kalanlar: {list(q)}")
        tur += 1
        
    return q[0]

kazanan = sicak_patates(["Ali", "Veli", "Ayşe", "Fatma", "Can", "Zeynep"], 2)
print(f"\n🏆 KAZANAN: {kazanan}")
Çıktı bekleniyor...

2. Yazıcı Kuyruğu (Printer Spooler)

Ofis yazıcısı simülasyonu. İşletim sistemlerinde spool (Simultaneous Peripheral Operations On-Line) kavramı.

Python Kodu
from collections import deque
import time

class Yazici:
    def __init__(self):
        self.kuyruk = deque()
        
    def belge_ekle(self, belge):
        self.kuyruk.append(belge)
        print(f"📥 Eklendi: {belge}")
        
    def yazdir(self):
        print("\n🖨️ Yazdırma Başlıyor...")
        while self.kuyruk:
            belge = self.kuyruk.popleft()
            print(f"   Çıktı alınıyor: {belge}...")
            # time.sleep(1) 
            print("   ✅ Tamamlandı.")
        print("🏁 Tüm belgeler yazdırıldı.")

ofis_yazicisi = Yazici()
ofis_yazicisi.belge_ekle("Rapor.pdf")
ofis_yazicisi.belge_ekle("Tez.docx")
ofis_yazicisi.belge_ekle("Fotoğraf.jpg")

ofis_yazicisi.yazdir()
Çıktı bekleniyor...

3. Sliding Window Maximum (Kayan Pencere)

🎯 Problem Ne Diyor?

Bir dizi üzerinde k boyutlu bir pencere kaydır. Her konumda pencere içindeki en büyük sayıyı bul.

Dizi: [1, 3, -1, -3, 5, 3]   k = 3
Pencere 1: [1, 3, -1, -3, 5, 3] → max = 3
Pencere 2: [1, 3, -1, -3, 5, 3] → max = 3
Pencere 3: [1, 3, -1, -3, 5, 3] → max = 5
Pencere 4: [1, 3, -1, -3, 5, 3] → max = 5
Sonuç: [3, 3, 5, 5]

❌ Naif Yöntem (Yavaş)

for her pencere:
    max(pencere)  # O(k) işlem

Toplam: O(n × k)
n=1000, k=100 → 100.000 işlem 😰

✅ Deque Yöntemi (Hızlı)

Her eleman 1 kez girer
Her eleman 1 kez çıkar

Toplam: O(n)
n=1000, k=100 → 1.000 işlem 🚀

💡 Ana Fikir: "Bully Algoritması"

Bir sıraya yeni biri geldiğinde:

👨‍🦲 → 🚪
Yeni eleman geldi
👨‍🦲 > 👦👧
Kendinden küçükleri kovar!
🏆 ← 👨‍🦲
En büyük hep önde!

Neden? Çünkü önündeki küçükler artık hiçbir zaman maksimum olamaz. Yeni gelen varken onlar asla kazanamaz, o yüzden niye tutayım?

📝 Elle Takip Edelim: [1, 3, -1, -3, 5], k=3

i Gelen Ne Oldu? Deque (indeksler) Deque (değerler) Sonuç
0 1 Deque boş, direkt ekle [0] [1] pencere dolmadı
1 3 3 > 1 → 1'i kov! Sonra 3 ekle [0] → [1] [3] pencere dolmadı
2 -1 -1 < 3 → kimseyi kovma, ekle [1, 2] [3, -1] 3 ✓
3 -3 -3 < -1 → kimseyi kovma, ekle [1, 2, 3] [3, -1, -3] 3 ✓
4 5 5 > -3, -1, 3 → hepsini kov!
+ indeks 1 pencere dışı (i-k+1 = 2)
[1,2,3] → [4] [5] 5 ✓
Sonuç: [3, 3, 5]

🔑 3 Basit Kural (Ezberle!)

1️⃣
Pencere dışını sil

Baştaki indeks pencere dışına çıktıysa → popleft()

2️⃣
Küçükleri kov

Yeni gelen > sondaki → pop() (döngüyle)

3️⃣
Ekle ve max al

Yeni indeksi sona ekle. Baştaki = max!

🎮 Kendin Dene!

DEQUE: ← MAX ... YENİ →
[ başla ]
▶️ Başlat butonuna tıklayın
Sonuç:
[ ]
Python Kodu (Basit Versiyon)
from collections import deque

def sliding_window_max(nums, k):
    dq = deque()   # İNDEKSLERİ tutuyoruz!
    sonuc = []
    
    for i in range(len(nums)):
        # 1️⃣ Pencere dışına çıkanı sil
        if dq and dq[0] < i - k + 1:
            dq.popleft()
        
        # 2️⃣ Küçükleri kov (yeni eleman büyükse)
        while dq and nums[dq[-1]] < nums[i]:
            dq.pop()
        
        # 3️⃣ Yeni indeksi ekle
        dq.append(i)
        
        # 4️⃣ Pencere dolduysa, baştaki = max
        if i >= k - 1:
            sonuc.append(nums[dq[0]])
    
    return sonuc

# Test
nums = [1, 3, -1, -3, 5, 3]
k = 3
print(f"Dizi: {nums}")
print(f"k = {k}")
print(f"Sonuç: {sliding_window_max(nums, k)}")
# Beklenen: [3, 3, 5, 5]
Çıktı bekleniyor...

✨ Özet: Neden Çalışıyor?

  • Deque'te indeksler tutulur (değerler değil)
  • Deque hep azalan sırada (baştaki en büyük)
  • Yeni gelen büyükse → önündeki küçükler artık asla max olamaz → kov!
  • Pencere kaydığında → eski indeks dışarı çıkar → sil
  • Her eleman 1 kez girer, 1 kez çıkar → O(n) 🚀

4. CPU Task Scheduler (Round Robin)

İşletim sistemlerinde kullanılan Round Robin scheduling algoritması. Her işleme eşit zaman dilimi (quantum) verilir.

Python Kodu
from collections import deque

def round_robin(islemler, quantum):
    """
    Round Robin CPU Scheduling
    islemler: [(isim, sure), ...]
    quantum: Her işleme verilen maksimum süre
    """
    kuyruk = deque()
    
    # İşlemleri kuyruğa ekle: [isim, kalan_sure]
    for isim, sure in islemler:
        kuyruk.append([isim, sure])
    
    zaman = 0
    print(f"⏰ Round Robin Scheduler (Quantum: {quantum}ms)\n")
    print("=" * 50)
    
    while kuyruk:
        islem = kuyruk.popleft()
        isim, kalan = islem
        
        # Bu turda çalışacak süre
        calisma = min(kalan, quantum)
        zaman += calisma
        kalan -= calisma
        
        if kalan > 0:
            # İşlem bitmedi, tekrar kuyruğa ekle
            print(f"⏳ t={zaman:3d}ms | {isim} çalıştı ({calisma}ms), kalan: {kalan}ms")
            kuyruk.append([isim, kalan])
        else:
            # İşlem tamamlandı
            print(f"✅ t={zaman:3d}ms | {isim} TAMAMLANDI!")
    
    print("=" * 50)
    print(f"🏁 Tüm işlemler tamamlandı. Toplam süre: {zaman}ms")

# Test
islemler = [
    ("Chrome", 10),
    ("VSCode", 8),
    ("Spotify", 6),
    ("Discord", 4)
]

round_robin(islemler, quantum=3)
Çıktı bekleniyor...

5. Rate Limiter (Hız Sınırlayıcı)

API'lerde kullanılan Sliding Window Rate Limiter. Belirli sürede maksimum istek sayısını sınırlar.

Python Kodu
from collections import deque
import time

class RateLimiter:
    """
    Sliding Window Rate Limiter
    Belirli sürede (window) maksimum istek sayısını (limit) sınırlar.
    """
    def __init__(self, limit, window_seconds):
        self.limit = limit
        self.window = window_seconds
        self.requests = deque()  # Timestamp'leri tutar
    
    def is_allowed(self, current_time):
        # Pencere dışındaki eski istekleri temizle
        while self.requests and self.requests[0] <= current_time - self.window:
            self.requests.popleft()
        
        # Limit kontrolü
        if len(self.requests) < self.limit:
            self.requests.append(current_time)
            return True
        return False

# Simülasyon
print("🚦 Rate Limiter Simülasyonu")
print("Limit: 5 istek / 10 saniye\n")

limiter = RateLimiter(limit=5, window_seconds=10)

# Test istekleri (zaman, kullanıcı)
test_istekler = [
    (0, "GET /api/users"),
    (1, "GET /api/posts"),
    (2, "POST /api/comment"),
    (3, "GET /api/profile"),
    (4, "PUT /api/settings"),
    (5, "GET /api/feed"),      # Bu reddedilmeli
    (6, "GET /api/messages"),  # Bu da
    (12, "GET /api/users"),    # 10 sn geçti, ilk istek düştü
    (13, "GET /api/posts"),    # İkinci istek de düştü
]

for zaman, endpoint in test_istekler:
    izin = limiter.is_allowed(zaman)
    durum = "✅ İZİN" if izin else "❌ REDDEDİLDİ"
    print(f"t={zaman:2d}s | {durum} | {endpoint}")
Çıktı bekleniyor...