📘 Asimptotik Notasyonlar - Ders Notu
🎯 O-Notasyonu (Big-O) - Üst Sınır
Tanım: Algoritmanın en kötü durum performansını gösterir.
f(n) = O(g(n)) ⟺ ∃c > 0, ∃n₀ ≥ 0 : ∀n ≥ n₀ → f(n) ≤ c·g(n) + b
Basit açıklama: f(n) fonksiyonu, yeterince büyük n değerleri için c·g(n)‘den daha hızlı büyümez.
📝 Örnek Çözüm
Soru: T(n) = 32n² + 17n + 32 için Big-O’yu bulun.
Cevap: T(n) = O(n²)
Açıklama:
- En yüksek dereceli terim: n²
- Diğer terimler (n, sabitler) n→∞ iken ihmal edilir
- ✅ O(n²) → DOĞRU
- ✅ O(n³) → DOĞRU (üst sınır da olur)
- ❌ O(n) → YANLIŞ (alt sınır olamaz)
İspat Örneği
Verilen: f(n) = 5n³ + 2n² + 22n + 6
Göster: f(n) = O(n³)
Çözüm:
Hedef: 5n³ + 2n² + 22n + 6 ≤ c·n³ için c ve n₀ bul
n₀ = 0 dene:
6 ≤ 0 → ❌ OLMAZ
n₀ = 1 dene:
5(1)³ + 2(1)² + 22(1) + 6 = 35
35 ≤ c·1³ → c = 35 seçilebilir ✅
SONUÇ: n₀ = 1, c = 35
📊 Diğer Notasyonlar
Ω-Notasyonu (Omega) - Alt Sınır
Algoritmanın en iyi durum performansını gösterir.
Θ-Notasyonu (Theta) - Sıkı Sınır
Hem üst hem alt sınırı gösterir (gerçek performans).
⚡ Karmaşıklık Seviyeleri
Hızdan yavaşa sıralama:
O(1) < O(log n) < O(n) < O(n log n) < O(n²) < O(n³) < O(2ⁿ)
Tanımlar
| Karmaşıklık | İsim | Örnek |
|---|---|---|
| O(1) | Sabit zaman | Diziye index ile erişim: arr[5] |
| O(n) | Doğrusal zaman | Tek döngü, dizide arama |
| O(n log n) | Logaritmik doğrusal | Merge Sort, Quick Sort |
| O(n²) | Karesel zaman | İç içe 2 döngü, Bubble Sort |
| O(n³) | Kübik zaman | İç içe 3 döngü, matris çarpımı |
🔥 Önemli Kurallar
1. Sabit Katsayılar İhmal Edilir
O(3n) = O(n)
O(n/2) = O(n)
O(100) = O(1)
2. En Büyük Terim Kazanır
O(n² + n) = O(n²)
O(5n³ + 2n² + 100n + 50) = O(n³)
3. Farklı Değişkenler Korunur
O(n + m) ≠ O(n) ← n ve m farklı
O(n × m) ≠ O(n²) ← n ≠ m ise
💻 Kod Örnekleri
# O(1) - Sabit zaman
def get_first(arr):
return arr[0]
# O(n) - Doğrusal zaman
def find_max(arr):
max_val = arr[0]
for num in arr: # n kez döner
if num > max_val:
max_val = num
return max_val
# O(n²) - Karesel zaman
def bubble_sort(arr):
for i in range(len(arr)): # n kez
for j in range(len(arr)-1): # n kez
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]
# O(log n) - Logaritmik zaman
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
📊 Performans Karşılaştırması
n = 1,000,000 için tahmini işlem sayıları:
| Karmaşıklık | İşlem Sayısı | Süre |
|---|---|---|
| O(1) | 1 | < 1 μs |
| O(log n) | ~20 | < 1 μs |
| O(n) | 1,000,000 | ~1 ms |
| O(n log n) | ~20,000,000 | ~20 ms |
| O(n²) | 1,000,000,000,000 | ~11.5 gün |
| O(n³) | 10¹⁸ | ~31,688 yıl |
💡 Pratik kural: n > 10,000 için O(n²) algoritmaları çok yavaştır!
🎯 Sık Yapılan Hatalar
❌ Yanlış: O(n² + n) yazmak
✅ Doğru: O(n²)
❌ Yanlış: O(3n) ≠ O(n) demek
✅ Doğru: O(3n) = O(n)
❌ Yanlış: O(n + m) = O(n) demek
✅ Doğru: O(n + m) olarak bırak (n ≠ m)
📚 Yaygın Sıralama Algoritmaları
| Algoritma | En İyi | Ortalama | En Kötü |
|---|---|---|---|
| Bubble Sort | O(n) | O(n²) | O(n²) |
| Selection Sort | O(n²) | O(n²) | O(n²) |
| Insertion Sort | O(n) | O(n²) | O(n²) |
| Merge Sort | O(n log n) | O(n log n) | O(n log n) |
| Quick Sort | O(n log n) | O(n log n) | O(n²) |
🔍 Hızlı Analiz İpuçları
Döngü sayısına bak:
- Tek döngü → O(n)
- İç içe 2 döngü → O(n²)
- İç içe 3 döngü → O(n³)
Özel durumlar:
- Her adımda yarıya iniyor → O(log n)
- Sıralama + arama → O(n log n)
- Tüm eleman çiftleri → O(n²)
📌 Sınav/Mülakat İpuçları
- İspatlarda n₀ ve c bul (genelde n₀ = 1 yeterli)
- En büyük terimi söyle (gerisi önemsiz)
- Döngü sayısını say (hızlı analiz için)
- Karşılaştırmalarda: küçük fonksiyon ≤ büyük fonksiyon