⚙️ 9.2: Heap Operasyonları

Insert, Delete, Heapify - Adım Adım Görselleştirme

🎯 Heap'te 3 Temel İşlem

➕ Insert (Ekleme)

Yeni eleman ekle → Heapify Up

Zaman: O(log n)

➖ Delete (Silme)

Kökü çıkar → Heapify Down

Zaman: O(log n)

🔄 Heapify

Diziyi heap'e dönüştür

Zaman: O(n) 🎉

➕ Insert (Ekleme) - Heapify Up

Heap'e yeni eleman eklemek için önce elemanı ağacın en sonuna (en alt seviyede, soldan ilk boş yere) ekliyoruz. Ama bu noktada heap özelliği bozulmuş olabilir - yeni eleman parent'ından büyük olabilir!

Bu sorunu çözmek için Heapify Up (yukarı yüzdürme / bubble up) işlemi yapıyoruz: Yeni elemanı parent'ı ile karşılaştırıp, gerekirse swap yaparak yukarı taşıyoruz. Köke ulaşana veya parent'tan küçük olana kadar devam ediyoruz.

📝 Insert Algoritması (Max Heap)

  1. Sona ekle: Yeni elemanı dizinin sonuna ekle (complete binary tree yapısı korunur)
  2. Parent bul: Parent indeksi = (i-1) // 2 formülü ile hesapla
  3. Karşılaştır: Eğer yeni eleman > parent → Yerlerini değiştir (swap)
  4. Tekrarla: Köke ulaşana (i=0) veya heap özelliği sağlanana kadar adım 2-3'ü tekrarla

Neden O(log n)? En kötü durumda, eleman kökten yapraklara kadar tırmanır. Ağacın yüksekliği log₂(n) olduğu için en fazla log n swap yapılır.

🧪 Insert Animasyonu (Max Heap)

Mevcut heap'e yeni değer ekleyin ve Heapify Up izleyin

➕ Yeni değer girin ve "Ekle" butonuna basın.

➖ Delete (Silme) - Heapify Down

Heap'te silme işlemi biraz farklı çalışır: sadece kök silinebilir. Neden? Çünkü heap'in amacı zaten en büyük (max heap) veya en küçük (min heap) elemana hızlı erişim sağlamak. Ortadaki bir elemanı silmek heap'in temel kullanım senaryosu değil.

Peki kökü nasıl siliyoruz? Direkt köküi silsek ağaç yapısı bozulur! Bunun yerine şu trick kullanılır:

  1. Kökü (max elemanı) bir kenara kaydet
  2. En son elemanı alıp köke koy (ağaç yapısı korunur, ama heap özelliği bozulur)
  3. Heapify Down ile kökteki elemanı aşağı batır

📝 Delete Algoritması (Max Heap)

  1. Kökü kaydet: Bu değer fonksiyonun sonunda döndürülecek
  2. Son elemanı köke taşı: heap[0] = heap[n-1]
  3. Diziyi küçült: Son elemanı sil (pop)
  4. Heapify Down: Kökten başla, her adımda daha büyük child ile swap yap
  5. Devam: Yaprakta olana veya çocuklarından büyük olana kadar tekrarla

Neden O(log n)? Insert'e benzer şekilde, en kötü durumda kökten yaprağa kadar iner. Yükseklik log₂(n) olduğu için O(log n).

🧪 Delete Animasyonu (Max Heap)

Kökü (en büyük) silme ve Heapify Down izleyin

➖ "Kökü Sil" butonuna basarak max elemanı çıkarın.

🔄 Heapify - Diziyi Heap'e Çevir

Elimizde rastgele sıralı bir dizi var ve bunu heap'e çevirmek istiyoruz. Bunun iki yolu var:

❌ Yavaş Yol: Tek tek insert
Boş heap'e n eleman ekle → n × O(log n) = O(n log n)
✅ Hızlı Yol: Build Heap
Diziyi yerinde heap'e çevir → O(n) 🎉

Build Heap algoritmasında, son parent'tan başlayarak (indeks n/2 - 1) geriye doğru her parent'a heapify_down uygularız. Yapraklar zaten tek başlarına geçerli heap oldukları için onları atlıyoruz.

🎯 Build Heap Neden O(n)? (Sezgisel Açıklama)

İlk bakışta n eleman × log n heapify = O(n log n) gibi görünür. Ama:

Başka bir bakış açısı: Her düğüm en fazla ağacın yüksekliği kadar hareket eder, ama çoğu düğüm (yapraklar) hiç hareket etmez!

Heapify - Python Implementasyonu
def heapify_down(arr, n, i):
    """i indeksindeki elemanı aşağı batır (Max Heap)"""
    largest = i
    left = 2 * i + 1
    right = 2 * i + 2

    # Sol child büyük mü?
    if left < n and arr[left] > arr[largest]:
        largest = left

    # Sağ child daha büyük mü?
    if right < n and arr[right] > arr[largest]:
        largest = right

    # Swap gerekli mi?
    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]
        print(f"   Swap: indeks {i} ({arr[largest]}) ↔ indeks {largest} ({arr[i]})")
        # Recursive olarak devam et
        heapify_down(arr, n, largest)

def build_max_heap(arr):
    """Rastgele diziyi max heap'e çevir - O(n)"""
    n = len(arr)
    print(f"Başlangıç dizisi: {arr}\n")

    # Son parent'tan başla: (n//2 - 1)
    # Yapraklar zaten heap özelliğini sağlıyor
    start = n // 2 - 1

    for i in range(start, -1, -1):
        print(f"🔽 Parent[{i}] = {arr[i]} batırılıyor...")
        heapify_down(arr, n, i)
        print(f"   Ara durum: {arr}")
        print()

    return arr

# Test
print("=== BUILD MAX HEAP ===\n")

arr = [4, 10, 3, 5, 1, 8, 7]
print(f"📋 Orijinal (rastgele) dizi: {arr}")
print("=" * 40)

heap = build_max_heap(arr.copy())

print("=" * 40)
print(f"✅ Sonuç (Max Heap): {heap}")
print(f"🔝 Kök (maksimum): {heap[0]}")

# Doğrulama
print("\n=== DOĞRULAMA ===")
print("Her parent ≥ children olmalı:")
for i in range(len(heap) // 2):
    left = 2 * i + 1
    right = 2 * i + 2
    msg = f"  [{i}]={heap[i]}"
    if left < len(heap):
        check = "✅" if heap[i] >= heap[left] else "❌"
        msg += f" ≥ L[{left}]={heap[left]} {check}"
    if right < len(heap):
        check = "✅" if heap[i] >= heap[right] else "❌"
        msg += f" ≥ R[{right}]={heap[right]} {check}"
    print(msg)
Çıktı bekleniyor...

🎮 İnteraktif Heap Builder

Kendi heap'inizi oluşturun ve operasyonları deneyin!

Max Heap Oyun Alanı

Heap boş. Yukarıdan sayı ekleyin veya "Rastgele" butonu ile başlayın!

📊 Karmaşıklık Özeti

İşlem Zaman Açıklama
Insert O(log n) Sona ekle + yukarı yüzdür
Delete (root) O(log n) Son elemanı köke taşı + aşağı batır
Peek (root) O(1) Sadece indeks 0'a bak
Build Heap O(n) Diziyi heap'e çevir (heapify)
Search O(n) Heap arama için optimize değil!

📋 Özet

✅ Bu Bölümde Öğrendikleriniz