🎯 6.2: İkili Arama (Binary Search)

Böl ve Fethet ile Logaritmik Hız

📌 Binary Search Nedir?

İkili Arama (Binary Search), sıralı bir dizide aranan elemanı bulmak için diziyi sürekli ikiye bölen çok verimli bir algoritmadır.

🔑 Temel Fikir: Böl ve Fethet (Divide & Conquer)

Her adımda arama alanı yarıya iner!

mid = (low + high) // 2

1.000.000 elemanlı dizide sadece ~20 karşılaştırma yeterli!

⚠️ ÖNEMLİ: Ön Koşul

Binary Search sadece SIRALI dizilerde çalışır!

Dizi sıralı değilse önce sıralamanız gerekir (O(n log n) maliyet).

🎬 Algoritma Adımları

  1. Başlangıç: low = 0, high = n-1 (tüm dizi)
  2. Orta noktayı bul: mid = (low + high) // 2
  3. Karşılaştır:
    • arr[mid] == target → BULUNDU! mid döndür
    • arr[mid] > target → Sağ yarıyı ele (high = mid - 1)
    • arr[mid] < target → Sol yarıyı ele (low = mid + 1)
  4. Tekrarla: low ≤ high olduğu sürece 2-3 adımlarını tekrarla
  5. Bulunamadı: low > high olunca -1 döndür

🎮 İnteraktif Binary Search Simülasyonu

Sıralı Dizi (15 eleman): [5, 11, 15, 22, 28, 34, 41, 45, 52, 58, 64, 71, 78, 85, 90]

🎯 Bir sayı girin ve "Ara" butonuna tıklayın...

📊 Karmaşıklık Analizi

🐢 Lineer Arama

O(n)

1.000.000 eleman = 1.000.000 karşılaştırma

🚀 Binary Search

O(log n)

1.000.000 eleman = ~20 karşılaştırma

Neden log₂(n)?

Her adımda arama alanı yarıya iniyor:

Adım Kalan Eleman Formül
0nn / 2⁰
1n/2n / 2¹
2n/4n / 2²
kn/2ᵏ = 1k = log₂(n)

💻 Python Implementasyonları

1. Iteratif (Döngü ile)

Python Kodu
def binary_search_iterative(arr, target):
    """
    İkili Arama - Iteratif Yöntem

    Args:
        arr: SIRALI dizi
        target: Aranan değer

    Returns:
        Bulunursa indeks, bulunamazsa -1
    """
    low = 0
    high = len(arr) - 1
    step = 0

    while low <= high:
        step += 1
        mid = (low + high) // 2

        print(f"Adım {step}: low={low}, high={high}, mid={mid}")
        print(f"         arr[{mid}] = {arr[mid]}")

        if arr[mid] == target:
            print(f"         ✅ BULUNDU!")
            return mid
        elif arr[mid] < target:
            print(f"         {arr[mid]} < {target} → Sağa git")
            low = mid + 1
        else:
            print(f"         {arr[mid]} > {target} → Sola git")
            high = mid - 1

    print("❌ Bulunamadı!")
    return -1

# Test
dizi = [11, 12, 22, 25, 34, 45, 64, 78, 90]
print(f"Sıralı Dizi: {dizi}")
print(f"Aranan: 45\n")

sonuc = binary_search_iterative(dizi, 45)
print(f"\nSonuç: İndeks = {sonuc}")
Çıktı bekleniyor...

2. Recursive (Özyinelemeli)

Python Kodu
def binary_search_recursive(arr, target, low, high, step=1):
    """
    İkili Arama - Recursive Yöntem
    """
    if low > high:
        return -1

    mid = (low + high) // 2
    print(f"Adım {step}: arr[{mid}] = {arr[mid]} {'✅' if arr[mid] == target else ''}")

    if arr[mid] == target:
        return mid
    elif arr[mid] < target:
        return binary_search_recursive(arr, target, mid + 1, high, step + 1)
    else:
        return binary_search_recursive(arr, target, low, mid - 1, step + 1)

# Test
dizi = [11, 12, 22, 25, 34, 45, 64, 78, 90]
print(f"Sıralı Dizi: {dizi}")
print(f"Aranan: 22\n")

sonuc = binary_search_recursive(dizi, 22, 0, len(dizi) - 1)
print(f"\nSonuç: İndeks = {sonuc}")

print("\n" + "="*40)
print("Recursive vs Iterative:")
print("- Recursive: Daha okunaklı, ama call stack kullanır")
print("- Iterative: Daha verimli (O(1) ek alan)")
Çıktı bekleniyor...

3. Python bisect Modülü

Python Kodu
import bisect

dizi = [11, 12, 22, 25, 34, 45, 64, 78, 90]
print(f"Sıralı Dizi: {dizi}")

# bisect_left: Elemanın eklenmesi gereken sol pozisyon
pos = bisect.bisect_left(dizi, 45)
print(f"\nbisect_left(45) = {pos}")

# Eleman var mı kontrol et
if pos < len(dizi) and dizi[pos] == 45:
    print(f"45 dizide var! İndeks: {pos}")
else:
    print("45 dizide yok")

# bisect_right: Elemanın eklenmesi gereken sağ pozisyon
# (Aynı elemanların sağına ekler)
print(f"\nbisect_right(45) = {bisect.bisect_right(dizi, 45)}")

# insort: Sıralı ekleme
print(f"\nOrijinal: {dizi}")
bisect.insort(dizi, 50)
print(f"50 eklendi: {dizi}")
Çıktı bekleniyor...

🧩 Yaygın Binary Search Varyasyonları

İlk ve Son Eşleşmeyi Bulma

Python Kodu
def find_first(arr, target):
    """Target'ın İLK göründüğü indeksi bulur"""
    low, high = 0, len(arr) - 1
    result = -1

    while low <= high:
        mid = (low + high) // 2
        if arr[mid] == target:
            result = mid       # Bulduk ama daha solda olabilir
            high = mid - 1     # Sola bakmaya devam
        elif arr[mid] < target:
            low = mid + 1
        else:
            high = mid - 1

    return result

def find_last(arr, target):
    """Target'ın SON göründüğü indeksi bulur"""
    low, high = 0, len(arr) - 1
    result = -1

    while low <= high:
        mid = (low + high) // 2
        if arr[mid] == target:
            result = mid       # Bulduk ama daha sağda olabilir
            low = mid + 1      # Sağa bakmaya devam
        elif arr[mid] < target:
            low = mid + 1
        else:
            high = mid - 1

    return result

# Test
dizi = [1, 2, 3, 3, 3, 3, 4, 5, 6]
print(f"Dizi: {dizi}")
print(f"Aranan: 3")

ilk = find_first(dizi, 3)
son = find_last(dizi, 3)

print(f"\nİlk 3'ün indeksi: {ilk}")
print(f"Son 3'ün indeksi: {son}")
print(f"3'ün sayısı: {son - ilk + 1}")
Çıktı bekleniyor...

🌍 Gerçek Hayat Kullanım Alanları

⚠️ Dikkat Edilmesi Gerekenler

Integer Overflow Problemi

Hatalı: mid = (low + high) / 2

Çok büyük sayılarda low + high taşabilir!

Doğru: mid = low + (high - low) // 2

Python'da otomatik big integer olduğu için sorun olmaz, ama C/Java'da dikkat!