Böl ve Fethet ile Logaritmik Hız
Divide & Conquer
Logaritmik hız
İki yaklaşım
Python hazır fonksiyon
İkili Arama (Binary Search), sıralı bir dizide aranan elemanı bulmak için diziyi sürekli ikiye bölen çok verimli bir algoritmadır.
Bir sözlükte "kalem" kelimesini arıyorsun. Ne yaparsın?
Baştan başlayıp tek tek sayfa çevirmek yerine, her seferinde yarısını eleyerek çok daha hızlı buldun!
Her adımda arama alanı yarıya iner!
1.000.000 elemanlı dizide sadece ~20 karşılaştırma yeterli!
Binary Search sadece SIRALI dizilerde çalışır!
Dizi sıralı değilse önce sıralamanız gerekir (O(n log n) maliyet).
Aşağıdaki sıralı dizide 45 sayısını arayalım:
dizi = [11, 22, 33, 45, 55, 66, 77, 88, 99]
low = 0, high = 8 → mid = (0+8) // 2 = 4
arr[4] = 55 → 55 > 45 → Sola git! (high = mid - 1 = 3)
low = 0, high = 3 → mid = (0+3) // 2 = 1
arr[1] = 22 → 22 < 45 → Sağa git! (low = mid + 1 = 2)
low = 2, high = 3 → mid = (2+3) // 2 = 2
arr[2] = 33 → 33 < 45 → Sağa git! (low = mid + 1 = 3)
low = 3, high = 3 → mid = (3+3) // 2 = 3
arr[3] = 45 → 45 == 45 → ✅ BULUNDU! return 3
Sıralı Dizi (15 eleman): [5, 11, 15, 22, 28, 34, 41, 45, 52, 58, 64, 71, 78, 85, 90]
O(n)
1.000.000 eleman = 1.000.000 karşılaştırma
O(log n)
1.000.000 eleman = ~20 karşılaştırma
log₂(n) şu soruyu cevaplar: "n sayısını kaç kez 2'ye bölersem 1 elde ederim?"
Sihir burada: Veri 2 katına çıkınca, adım sayısı sadece 1 artıyor! Bu yüzden Binary Search büyük verilerde muazzam hızlı.
Her adımda arama alanı yarıya iniyor:
| Adım | Kalan Eleman | Formül |
|---|---|---|
| 0 | n | n / 2⁰ |
| 1 | n/2 | n / 2¹ |
| 2 | n/4 | n / 2² |
| k | n/2ᵏ = 1 | k = log₂(n) |
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}")
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)")
Python'un bisect modülü, binary search'ü sizin için yapan hazır bir kütüphanedir. "Bisect" kelimesi İngilizce'de "ikiye bölmek" anlamına gelir.
x'in eklenmesi gereken sol pozisyonu bulur. Aynı değerden varsa soluna ekler.
x'in eklenmesi gereken sağ pozisyonu bulur. Aynı değerden varsa sağına ekler.
x'i sıralı diziye doğru pozisyona ekler. Hem bulur hem ekler!
Neden kullanmalı? Kendi binary search'ünüzü yazmak yerine, test edilmiş ve optimize edilmiş bu modülü kullanmak daha güvenlidir.
# ==========================================
# PYTHON BISECT MODÜLÜ - HAZIR BINARY SEARCH
# ==========================================
import bisect
dizi = [11, 12, 22, 25, 34, 45, 64, 78, 90]
print(f"📋 Sıralı Dizi: {dizi}")
print("=" * 50)
# --------- bisect_left ---------
# x değerinin eklenmesi gereken EN SOL pozisyonu bulur
# Eğer x zaten varsa, mevcut x'lerin SOLUNA ekler
print("\n🔍 bisect_left örnekleri:")
pos = bisect.bisect_left(dizi, 45)
print(f" bisect_left(45) = {pos}")
print(f" → 45 dizide {'VAR' if pos < len(dizi) and dizi[pos] == 45 else 'YOK'}!")
# Olmayan bir değer için
pos2 = bisect.bisect_left(dizi, 30)
print(f" bisect_left(30) = {pos2}")
print(f" → 30 olsaydı indeks {pos2}'e eklenmeli (25 ile 34 arasına)")
# --------- bisect_right ---------
# x değerinin eklenmesi gereken EN SAĞ pozisyonu bulur
print("\n🔍 bisect_right örneği:")
tekrarli = [1, 2, 3, 3, 3, 3, 4, 5]
print(f" Dizi: {tekrarli}")
print(f" bisect_left(3) = {bisect.bisect_left(tekrarli, 3)} (ilk 3'ün soluna)")
print(f" bisect_right(3) = {bisect.bisect_right(tekrarli, 3)} (son 3'ün sağına)")
# --------- insort ---------
# Elemanı sıralı şekilde ekler (bul + ekle tek adımda)
print("\n🔍 insort örneği:")
print(f" Orijinal: {dizi}")
bisect.insort(dizi, 50)
print(f" 50 eklendi: {dizi}")
print(f" → 50, sırayı bozmadan doğru yere yerleşti!")
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}")
Binary Search, yazılım dünyasının en temel ve en güçlü algoritmalarından biridir. Sadece "dizide eleman bulma" değil, çok daha geniş bir problem sınıfında kullanılır.
Bir algoritma, sorduğu soruya göre arama alanını yarıya indirebiliyorsa - orada binary search mantığı vardır!
Birçok ileri algoritma, binary search'ü bir "alt rutin" olarak kullanır:
Ağaç yapısında arama, ekleme, silme - hepsi binary search mantığıyla O(log n).
"Böl ve fethet" mantığı - sıralama algoritmalarının temeli.
O(n²)'dan O(n log n)'e düşürmek için binary search kullanılır.
Sıralı dizide ekleme pozisyonu, aralık sorguları - C++ STL'de std::lower_bound.
Cevap üzerinde arama! "Minimum maksimum", "maksimum minimum" problemlerinde.
MySQL, PostgreSQL indeksleri - milyarlarca kayıtta milisaniye erişim.
| Veri Boyutu (n) | Linear O(n) | Binary O(log n) | Hız Farkı |
|---|---|---|---|
| 1,000 | 1,000 adım | 10 adım | 100x hızlı |
| 1,000,000 | 1,000,000 adım | 20 adım | 50,000x hızlı |
| 1,000,000,000 | 1 milyar adım 😱 | 30 adım | 33,000,000x hızlı |
FAANG ve büyük teknoloji şirketlerinin mülakatlarında binary search çok sık sorulur. LeetCode'daki problemlerin yaklaşık %15-20'si doğrudan veya dolaylı olarak binary search kullanır. "Binary Search on Answer" paterni özellikle popülerdir!
Bilgisayarlarda sayılar sınırlı bit ile saklanır. Örneğin 32-bit integer en fazla 2,147,483,647 (yaklaşık 2 milyar) değerini tutabilir. Bu sınırı aşarsan ne olur?
low = 1,500,000,000 (1.5 milyar)high = 2,000,000,000 (2 milyar)low + high = 3,500,000,000 ❌ 32-bit sınırını aştı!Sonuç: Sayı "taşar" ve negatif veya beklenmedik bir değer olur → Program çöker veya yanlış sonuç verir!
mid = (low + high) / 2
low + high toplamı taşabilir!
mid = low + (high - low) // 2
high - low asla taşmaz!
Python otomatik olarak büyük sayıları yönetir (arbitrary precision integers). Sınır yok! Ama C, C++, Java gibi dillerde 32/64-bit sınırı vardır, bu yüzden iş görüşmelerinde bu konuyu bilmek önemli.
Böl ve Fethet - Her adımda yarıya böl
O(log n) - Logaritmik
O(1) Iteratif / O(log n) Recursive
Dizi SIRALI olmalı!
Pratik yapmak ister misin?
👉 Arama Algoritmaları Örnek Sorular sayfasına göz at!