Big O Nedir? (Ve Neden Önemsemelisiniz?)
Bir itirafla başlayayım: "Big O notasyonu"nu ilk duyduğumda, sadece bilgisayar bilimi profesörlerinin umursadığı ileri düzey bir matematik konusu olduğunu düşünmüştüm. Spoiler — yanılmışım. Hem de çok.
Big O notasyonu, kodunuzun girdi büyüdükçe nasıl yavaşladığını tanımlamanın basit bir yoludur. Hepsi bu. Ne daha fazla, ne daha az.
Şöyle düşünün: 10 elemanla mükemmel çalışan bir fonksiyon yazıyorsunuz. Harika. Ama patronunuz "artık 10 milyon kullanıcımız var" dediğinde ne olacak? Fonksiyonunuz hâlâ milisaniyeler içinde çalışacak mı? Yoksa tıkanıp kalacak mı?
İşte Big O tam olarak bunu söyler. Şu sorunun cevabıdır: "Kodum ölçeklendiğinde nasıl davranır?"
Gerçek Dünyada Neden Önemli
Şöyle gerçek bir senaryo gördüm. Bir geliştirici, iç içe döngüler kullanarak bir arama fonksiyonu yazıyor. 100 elemanla test sırasında gayet güzel çalışıyor. Sonra 100.000 elemanla canlıya çıkıyor. Sayfa 47 saniyede yükleniyor. Kullanıcılar gidiyor. Para kaybediliyor.
Eğer o geliştirici Big O'yu anlasaydı, O(n²) çözümünün saatli bir bomba olduğunu bilir ve bunun yerine hash map'e (O(1) arama) yönelirdi.
Big O akademik teori değildir. Canlıda gerçekten çalışan kod yazmak için hayatta kalma becerisidir.
Her Şeyi Basitleştiren Tek Kural
Big O'nun güzel tarafı şu — her bir işlemi saymanıza gerek YOK. Sadece baskın terimi belirleyin ve gerisini atın:
O(3n + 500)→ O(n) — sabitler ölçekte önemli değilO(n² + 5n + 100)→ O(n²) — en büyük terim kazanırO(500)→ O(1) — sabit sayıda adım her zaman sabittir- Two Sum — O(n²) yerine O(n)'de yapabilir misiniz?
- Binary Search — Klasik O(log n) algoritması
- Contains Duplicate — O(n²) kaba kuvvet ile O(n) hash set karşılaştırması
- Maximum Subarray — Kadane algoritması O(n) başarır
- Merge Sort — Böl-ve-fethet'in neden O(n log n) verdiğini anlayın
- O(1) anlık. O(log n) neredeyse anlık. O(n) adil. O(n log n) sıralamanın en iyisi. O(n²) tehlikeli. O(2ⁿ) felaket.
- Döngüleri sayın. Sabitleri atın. En büyük terimi tutun.
- Kodunuz yavaşsa ilk soru: "Bunun Big O'su ne?"
Neden? Çünkü Big O, ölçekteki davranışı tanımlar. n küçükken her şey hızlıdır. n devasa olduğunda sadece baskın terim önemlidir.
Uygulamada Görün
Aşağıdaki interaktif grafik, 6 yaygın karmaşıklığı birlikte gösteriyor. Her birini adım adım görmek için oynat tuşuna basın veya okları kullanın:
<iframe src="/tr/dsa/embed.html?topic=0&lang=tr" width="100%" height="200" style="border:none;border-radius:12px;overflow:hidden" loading="lazy"></iframe>
Her Karmaşıklığı Parçalayalım (Gerçek Örneklerle)
Şimdi en hızlıdan en yavaşa, her karmaşıklık sınıfını inceleyelim. Her biri için ne anlama geldiğini, nerede gördüğünüzü ve neden önemli olduğunu açıklayacağım.
O(1) — Sabit Zaman: Kutsal Kase
Ne anlama gelir: Girdiniz ne kadar büyük olursa olsun — 10 eleman veya 10 milyar eleman — işlem aynı sürede tamamlanır.
Nerede görürsünüz: İndeksle dizi erişimi, hash map aramaları, yığına eleman ekleme.
Neden önemli: Bir problemi O(1)'de çözebiliyorsanız, kazandınız demektir.
O(log n) — Logaritmik: İnanılmaz Hızlı
Ne anlama gelir: Her adımda kalan iş yarıya iner. 1 milyon eleman? Yaklaşık 20 adım. 1 milyar eleman? Yaklaşık 30 adım.
Nerede görürsünüz: İkili arama, dengeli ikili ağaç işlemleri.
Neden önemli: Pratikte O(1)'e neredeyse eşittir.
O(n) — Doğrusal: Adil ve Dürüst
Ne anlama gelir: Süre doğrudan girdiyle büyür. 10 eleman = 10 adım. 1 milyon eleman = 1 milyon adım.
Nerede görürsünüz: Diziyi bir kez tarama, max/min bulma, eleman sayma.
Neden önemli: Her elemana bakmanız gerekiyorsa, O(n) en iyidir. Temel çizgidir.
O(n log n) — Doğrusal-Logaritmik: Sıralamanın Tatlı Noktası
Ne anlama gelir: Doğrusallığın biraz üstünde. n elemanın her biri için log n işlem yapılır.
Nerede görürsünüz: Merge sort, quick sort, heap sort.
Neden önemli: Karşılaştırma tabanlı sıralama için teorik sınırdır.
O(n²) — Karesel: Sessiz Katil
Ne anlama gelir: Süre, girdinin karesiyle büyür. 10 eleman = 100 adım. 1.000 eleman = 1.000.000 adım.
Nerede görürsünüz: İç içe döngüler, bubble sort, selection sort.
Neden önemli: Küçük girdilerde sorunsuz ama n büyüdükçe patlıyor.
O(2ⁿ) — Üstel: Kaçın
Ne anlama gelir: Her ek eleman toplam işi İKİYE KATLAR. 10 eleman = 1.024 adım. 20 eleman = 1 milyondan fazla.
Nerede görürsünüz: Tüm alt kümeleri oluşturma, memoizasyonsuz özyinelemeli Fibonacci.
Neden önemli: n < 25 garanti değilse, her ne pahasına olursa olsun kaçının.
Kod Örnekleri
Python
# O(1) - Sabit: tek bir erişim, döngü yok def get_first(arr: list): return arr[0] if arr else None# O(n) - Doğrusal: tek döngü def find_max(arr: list) -> int: max_val = arr[0] for num in arr: # n kez if num > max_val: max_val = num return max_val
# O(n²) - Karesel: iç içe döngüler = n × n def has_duplicate(arr: list) -> bool: for i in range(len(arr)): # n kez for j in range(i + 1, len(arr)): # × n kez if arr[i] == arr[j]: return True return False
Java
// O(1) - Sabit: doğrudan dizi erişimi public static int getFirst(int[] arr) { return arr[0]; }// O(n) - Doğrusal: tek döngü public static int findMax(int[] arr) { int max = arr[0]; for (int num : arr) { // n kez if (num > max) max = num; } return max; }
// O(n²) - Karesel: iç içe döngüler public static boolean hasDuplicate(int[] arr) { for (int i = 0; i < arr.length; i++) { // n kez for (int j = i + 1; j < arr.length; j++) { // × n kez if (arr[i] == arr[j]) return true; } } return false; }
Herhangi Bir Kodun Karmaşıklığını Belirleme
1. Döngüleri sayın. Döngü yok = O(1). Tek döngü = O(n). İki iç içe = O(n²). 2. Veriyi yarılıyor mu? Her iterasyon işi yarıya indiriyorsa O(log n). 3. Özyinelemeye bakın. Kendini iki kez çağırıyorsa muhtemelen O(2ⁿ). 4. Sabitleri atın. O(3n + 10) = O(n). O(n² + n) = O(n²). 5. Adlandırın. O(1) sabit, O(log n) logaritmik, O(n) doğrusal, O(n²) karesel, O(2ⁿ) üstel.
Pratik Problemler
Sonuç
Big O, kulağa korkutucu gelen ama aslında sezgiyi yakaladığınızda basit olan kavramlardan biridir:
Bir sonraki yazıda alan karmaşıklığından bahsedeceğiz. Çünkü tüm RAM'inizi yiyen hızlı kod, yavaş koddan iyi değildir. Orada görüşürüz.


Yorumlar (