🔄 3.2: Normal Queue Problemi ve Circular Queue

Neden Dairesel Kuyruk Gerekli?

🤔 Önce Normal (Linear) Queue'yu Anlayalım

Bir diziyi queue olarak kullandığımızda head (baş) ve tail (kuyruk) pointer'ları kullanırız:

Normal (Linear) Queue - Problem Gösterimi
# Normal (Linear) Queue - Problem Gösterimi
# Sabit boyutlu dizi ile queue

capacity = 5
queue = [None] * capacity  # 5 hücreli boş dizi
head = 0  # Çıkacak elemanın indeksi
tail = 0  # Yeni elemanın ekleneceği indeks

def show_queue():
    """Queue durumunu göster"""
    print(f"Queue: {queue}")
    print(f"Head: {head}, Tail: {tail}")
    print()

# 1. Elemanlar ekleyelim
print("=== Ekleme (Enqueue) ===")
for val in ['A', 'B', 'C', 'D', 'E']:
    if tail < capacity:
        queue[tail] = val
        tail += 1
        print(f"'{val}' eklendi")
show_queue()

# 2. Bazı elemanları çıkaralım
print("=== Çıkarma (Dequeue) ===")
for _ in range(2):
    if head < tail:
        val = queue[head]
        queue[head] = None
        head += 1
        print(f"'{val}' çıkarıldı")
show_queue()

# 3. Yeni eleman eklemeye çalışalım
print("=== Problem! ===")
print(f"tail = {tail}, capacity = {capacity}")
print(f"Başta {head} boş hücre var ama...")
if tail >= capacity:
    print("❌ tail >= capacity → Ekleyemiyoruz!")
    print("   Bu 'False Overflow' problemidir.")
Çıktı bekleniyor...

🎯 Problemi Görselleştirelim

❌ Normal Queue Problemi: "False Overflow"

tail=5 oldu ama dizi boyutu 5. Başta 2 hücre boş olmasına rağmen yeni eleman ekleyemiyoruz!

✅ Çözüm: Circular Queue (Modülo ile)

Pointer'ları % capacity ile sarmalayarak dizinin başına dönebiliriz:

tail = (tail + 1) % capacity  # 5 % 5 = 0 (başa döner!)
head = (head + 1) % capacity

Bu sayede dizi dairesel olarak kullanılır ve hafıza israfı önlenir.

🔄 Circular Queue Görsel Simülasyonu

Head: 0, Tail: 0

💻 Circular Queue - Numpy Implementasyonu

Python Kodu
# Circular Queue - Modülo ile Çözüm

capacity = 5
queue = [None] * capacity
head = 0
tail = 0
size = 0  # Eleman sayısını takip et

def is_full():
    return size == capacity

def is_empty():
    return size == 0

def enqueue(val):
    global tail, size
    if is_full():
        print(f"❌ Queue dolu, '{val}' eklenemedi")
        return
    queue[tail] = val
    tail = (tail + 1) % capacity  # Modülo ile sarmal!
    size += 1
    print(f"✅ '{val}' eklendi (tail → {tail})")

def dequeue():
    global head, size
    if is_empty():
        print("❌ Queue boş")
        return None
    val = queue[head]
    queue[head] = None
    head = (head + 1) % capacity  # Modülo ile sarmal!
    size -= 1
    print(f"🔄 '{val}' çıkarıldı (head → {head})")
    return val

def show():
    print(f"Queue: {queue}")
    print(f"Head: {head}, Tail: {tail}, Size: {size}\n")

# Test
print("=== Circular Queue Demo ===\n")

# Doldur
for c in ['A', 'B', 'C', 'D', 'E']:
    enqueue(c)
show()

# 2 çıkar
dequeue()
dequeue()
show()

# Şimdi yeni eleman ekleyebiliriz!
print("=== Artık başa dönebiliyoruz! ===")
enqueue('F')
enqueue('G')
show()

print("✅ False overflow problemi çözüldü!")
Çıktı bekleniyor...

📊 Linear vs Circular Queue Karşılaştırması

Özellik Linear Queue Circular Queue
Hafıza Kullanımı ❌ İsraf var (false overflow) ✅ Tam verimli
Pointer Güncelleme tail++ tail = (tail+1) % cap
Doluluk Kontrolü tail == capacity size == capacity
Zaman Karmaşıklığı O(1) O(1)

🔢 Modülo (%) Operatörü Nasıl Çalışır?

Modülo, bölme işleminin kalanını verir. Aşağıdaki butona tıklayarak dene!

🎮 Modülo Simülatörü (Kapasite = 5)

0 % 5 = 0
0
1
2
3
4

⏰ Gerçek Hayat: Saat Kadranı

Saat 12'den sonra 1'e döner, tıpkı modülo gibi!

12 saat + 3 saat = 15 → 15 % 12 = 3 (saat 3)