Algoritmalar ve karmaşıklık konusunu sıfırdan öğrenin
1Karmaşıklık neyi ölçer
Algoritma, bir problemi çözen sonlu bir kesin adımlar listesidir; örneğin bir listeyi sıralamak ya da telefon rehberinde bir isim bulmak.
İki algoritma aynı problemi çözebilir ama çok farklı sürelerde. Karmaşıklık, girdi büyüdükçe işin nasıl büyüdüğünü anlatır.
Girdinin boyutuna n denir: sıralanacak öğe sayısı, bir listenin uzunluğu, bir graftaki düğüm sayısı.
1000 sayfalık bir telefon rehberinde isim aradığınızı düşünün. Her sayfayı okumak en fazla 1000 adım sürer. Ortadan açıp her seferinde yarıya bölmek yaklaşık 10 adım sürer.
Zaman karmaşıklığı adımları sayar. Alan karmaşıklığı ekstra belleği sayar. İkisi de n’nin bir fonksiyonu olarak yazılır.
Genellikle en kötü duruma bakılır: n boyutlu tüm girdiler içinde en çok iş. Bazen bunun yerine ortalama durum ya da en iyi durum sorulur.
Kendini sına İşi n² gibi büyüyen bir algoritma n = 1000 için 1 saniye sürüyor. n = 2000 için yaklaşık ne kadar sürer?
- 1 saniye
- 2 saniye
- 4 saniye
- 8 saniye
Cevap: 4 saniye. n’yi ikiye katlamak n²’yi 2² = 4 ile çarpar, bu yüzden süre yaklaşık 1’den yaklaşık 4 saniyeye çıkar. 2 saniye doğrusal büyüme için, 8 ise n³ için cevap olurdu.
2Büyük O ve büyüme sınıfları
Büyük O gösterimi yalnızca büyük n için önemli olanı tutar. Sabit çarpanları atar ve yalnızca en hızlı büyüyen terimi tutarsınız.
3n² + 5n + 2 ⇒ O(n²)
n = 1000 için n² terimi 3 000 000’dur, 5n ise yalnızca 5000. Küçük terimler toplamı pek değiştirmez.
Bu sınıflar, en yavaştan en hızlı büyümeye doğru tekrar tekrar karşınıza çıkar:
- O(1), sabit: bir dizi öğesini indeksiyle okumak.
- O(log n), logaritmik: her adımda problemi yarıya bölen ikili arama.
- O(n), doğrusal: en büyük değeri bulmak gibi tüm öğeler üzerinde tek geçiş.
- O(n log n): birleştirmeli sıralama (merge sort) gibi iyi sıralama algoritmaları.
- O(n²), ikinci dereceden: öğeler üzerinde iç içe iki döngü, kabarcık sıralaması (bubble sort) gibi.
- O(2ⁿ), üstel: her alt kümeyi denemek. Çabucak kullanılamaz hâle gelir.
Büyük O bir üst sınırdır: iş en fazla bu hızla büyür. Ω (Büyük Omega) bir alt sınırdır ve Θ (Teta) hem üst hem alt olan sıkı bir sınırdır.
Logaritmanın tabanı Büyük O’da önemli değildir, çünkü farklı tabanlı logaritmalar yalnızca sabit bir çarpanla ayrılır.
Kendini sına 4n + 2n² + 100’ün Büyük O’su nedir?
- O(100)
- O(2n²)
- O(n)
- O(n²)
Cevap: O(n²). Büyük n için n² terimi baskındır ve 2 sabit çarpanı atılır. O(n) yanlış terimi tutar ve O(2n²) sabiti atmayı unutur.
3Arama, sıralama ve özyineleme
Birkaç algoritma hemen her derste karşınıza çıkar. Karmaşıklıklarını olgu olarak öğrenin.
- Doğrusal arama öğeleri tek tek kontrol eder: O(n). İkili arama sıralı bir dizi gerektirir ve her adımda aralığı yarıya böler: O(log n).
- Kabarcık, ekleme ve seçme sıralaması iç içe döngülerde öğeleri karşılaştırır ve değiştirir: O(n²). Ekleme sıralaması zaten sıralı bir dizide O(n)’dir.
- Birleştirmeli sıralama diziyi yarılara böler, sıralar ve birleştirir: her durumda O(n log n), O(n) ekstra bellekle.
- Hızlı sıralama (quicksort) bir pivot etrafında böler: ortalamada O(n log n), ama en kötü durumda O(n²); örneğin ilk öğenin pivot olduğu sıralı bir dizi.
- Yalnızca öğeleri karşılaştıran hiçbir sıralama en kötü durumda Ω(n log n)’i geçemez. Sayma sıralaması karşılaştırma yapmadığı için daha hızlıdır.
Özyinelemeli bir fonksiyon, doğrudan cevapladığı bir temel duruma ulaşana kadar kendini daha küçük bir girdiyle çağırır. Çalışma süresi bir özyineleme bağıntısı olarak yazılır:
- T(n) = T(n/2) + O(1), ikili arama gibi O(log n) verir.
- T(n) = 2T(n/2) + O(n), birleştirmeli sıralama gibi O(n log n) verir.
- T(n) = T(n − 1) + O(n), O(n²) verir.
- T(n) = 2T(n − 1) + O(1), O(2ⁿ) verir.
Üç tasarım fikrini bilmekte yarar var. Böl ve fethet böler, çözer ve birleştirir. Açgözlü (greedy) her adımda yerel olarak en iyi seçimi yapar. Dinamik programlama örtüşen alt problemlerin cevaplarını saklar, böylece bir kez hesaplanırlar.
Kendini sına Hızlı sıralamanın en kötü durum zaman karmaşıklığı nedir?
- O(log n)
- O(n log n)
- O(n)
- O(n²)
Cevap: O(n²). Kötü pivotlarla her bölme n − 1 öğeyi bir tarafta bırakır, bu da O(n²) verir. O(n log n) onun ortalama durumudur ve birleştirmeli sıralamanın en kötü durumudur.
4Adım adım yöntem
Bir kod parçasının zaman karmaşıklığını bulmak için:
- n’nin ne olduğuna karar verin: girdinin boyutu.
- Her döngünün kaç kez çalıştığını sayın. Her seferinde 1 ekleyen döngü yaklaşık n kez çalışır. İkiye katlayan ya da yarıya bölen döngü yaklaşık log₂ n kez çalışır.
- İç içe döngüler çarpılır. Art arda gelen döngüler toplanır.
- Özyinelemeli bir fonksiyon için özyineleme bağıntısını yazın: kaç çağrı, hangi boyutta, artı çağrı başına iş.
- En hızlı büyüyen terimi tutun ve sabitleri atın.
- Küçük bir sayıyla kontrol edin, örneğin n = 8 ya da n = 1024.
Bir teori sorusunda önce anlattığı algoritmayı veya fikri adlandırın, sonra karmaşıklığını ve koşullarını (sıralı girdi, negatif olmayan ağırlıklar, örtüşen alt problemler) hatırlayın.
5Çözümlü bir örnek
Her adımı izleyin. Açmadan önce bir sonrakini tahmin etmeye çalışın.
Çözümlü örnekBu kodun zaman karmaşıklığı nedir? for i = 1 to n: (j = 1; while j < n: j = j × 2)
1n, döngülerin çalıştığı üst sayıdır.
2i, 1’den n’ye 1’er adımla gider, bu yüzden dış döngü n kez çalışır.
3j, 1, 2, 4, 8, … değerlerini alır ve n’ye ulaşınca durur. k turdan sonra j = 2k’dir, bu yüzden döngü yaklaşık log₂ n turdan sonra durur.
4İç döngü dış döngünün içindedir, bu yüzden sayılar çarpılır.
n · log₂ n ⇒ O(n log n)
5n = 1024 için iç döngü log₂ 1024 = 10 kez çalışır, bu yüzden gövde 1024 · 10 = 10 240 kez çalışır. Bu, n² = 1 048 576’dan çok daha azdır.
6Sık yapılan hatalar
- Art arda çalışan döngüleri çarpmak. n + n = 2n hâlâ O(n)’dir.
- O(2n) ya da O(n/2) gibi sabitleri tutmak. İkisi de O(n)’dir.
- İkiye katlayan bir döngüyü n tur saymak. Yaklaşık log₂ n kez çalışır.
- İkili aramayı sıralanmamış veriye ya da ortasına tek adımda ulaşılamayan bağlı listeye uygulamak.
- En kötü durum sorulduğunda hızlı sıralamanın ortalama durumunu vermek.
- Büyük O’nun “tam olarak” anlamına geldiğini sanmak. O(n²) bir üst sınırdır; Θ(n²) tam büyümedir.
Kendini sına Bir fonksiyon n yinelemeli bir döngü çalıştırıyor ve sonra ayrıca n yinelemeli bir döngü daha çalıştırıyor. Zaman karmaşıklığı nedir?
- O(2n)
- O(log n)
- O(n)
- O(n²)
Cevap: O(n). Art arda gelen döngüler toplanır: n + n = 2n ve sabit atılır, yani O(n). O(n²) yalnızca bir döngü diğerinin içindeyse doğru olurdu.
7Sınav soruları nasıl görünür
- Kolay: anahtar terimler ve olgular. İkili aramanın, birleştirmeli sıralamanın veya dizi erişiminin karmaşıklığı, O, Ω ve Θ’nın anlamı, özyinelemenin ne olduğu.
- Orta: kavramları uygulama. Bir kod parçasının karmaşıklığı, çözülecek bir özyineleme bağıntısı, n ikiye katlanınca sürenin nasıl değiştiği, bir göreve hangi algoritmanın uyduğu.
- Zor: olgular ve analiz. Ana teorem (master theorem), hızlı sıralamanın en kötü durumları, açgözlü ve dinamik programlama karşılaştırması ve P, NP ve NP-tam sınıfları.
P, polinom zamanda çözülebilen problemleri içerir. NP, çözümleri polinom zamanda kontrol edilebilen problemleri içerir. P’deki her problem NP’dedir; P = NP olup olmadığı hâlâ bilinmiyor.
Uygulamada adım adım öğreninUygulamada adım adım öğrenin