Bölüm 1.2: Algoritma Karmaşıklığı

Algoritmalar
Zaman ve bellekEn iyi / en kötü / ortalamaBüyük O, Ω, ΘBüyüme sınıfları Döngü analiziYineleme bağıntılarıAna Teoremf1–f6 örnekleri
Sercan KÜLCÜ · Giresun Üniversitesi · Bilgisayar Mühendisliği

Giriş

Öğrenme Çıktıları

Kavramlar

Zaman ve alan karmaşıklığını, en iyi, en kötü ve ortalama durum analizini birbirinden ayırmak.

Gösterim

Büyük O, Ω ve Θ tanımlarını yazmak; bir fonksiyon için c ve n₀ sabitlerini bularak sınır kanıtlamak.

Döngü analizi

Tek, iç içe ve çarpımsal döngülerin adım sayısını toplam formülleriyle hesaplamak (f1, f2, f6).

Özyineleme

Özyinelemeli kod için bağıntı kurmak; açma, özyineleme ağacı ve Ana Teorem ile çözmek (f3, f4, f5).

Bölüm boyunca altı kısa örnek fonksiyon (f1–f6) üzerinde çalışacağız: her biri farklı bir büyüme sınıfını (n, n³, 2ⁿ, n, n log n, log* n) temsil eder.

Karmaşıklık Kavramı

Algoritma Karmaşıklığı

  • Karmaşıklık teorisi (complexity theory), bir algoritmanın kaynak kullanımını ölçer: zaman ve bellek.
  • Kaynak kullanımı, girdi boyutu n'nin bir fonksiyonu olarak yazılır: T(n), S(n).
  • Amaç saniye ölçmek değil, girdi büyüdükçe kaynak ihtiyacının nasıl büyüdüğünü görmektir.
Zaman karmaşıklığı (time complexity)Algoritmanın yaptığı temel işlem sayısı: atama, karşılaştırma, aritmetik işlem, dizi erişimi.
Alan karmaşıklığı (space complexity)Algoritmanın girdiye ek olarak kullandığı bellek: değişkenler, yardımcı diziler, özyineleme yığını.
×1O(1)+1 adımO(log n)×2O(n)×4O(n²)×8O(n³)
Temel soru: Girdi boyutu iki katına çıktığında çalışma süresi ne olur? Aynı mı kalır, iki katına mı, dört katına mı çıkar, yoksa karesi mi alınır?

Karmaşıklık Kavramı

Süre Ölçümü Neden Yetmez?

long baslangic = System.currentTimeMillis();
dogrusalArama(dizi, 10001);  // 10^8 eleman
long bitis = System.currentTimeMillis();
System.out.println("Geçen süre: "
    + (bitis - baslangic) + " ms");
  • Bu kod 10⁸ öğeli bir dizide doğrusal aramanın süresini ölçer.
  • Sonuç makineye, işlemciye, JIT derleyicisine, önbelleğe ve o anki yüke göre değişir.
  • Tek bir ölçüm, girdi büyüyünce ne olacağını söylemez.
makine A: 2nmakine B: 5nn²/4nsüre
Deneysel ölçümGerçek süreyi verir ama makineye bağlıdır; kodun yazılmış olması gerekir.
Asimptotik analizAdım sayısını n'nin fonksiyonu olarak verir; makineden bağımsızdır, kod yazmadan yapılabilir.

Karmaşıklık Kavramı

Adım Sayma: dogrusalArama

for (int i = 0; i < a.length; i++) {
  if (a[i] == hedef)
    return i;
}
return -1;
İşlemEn kötü sayı
i = 01
i < a.lengthn + 1
a[i] == hedefn
i++n
return -11
Toplam T(n)3n + 3
  • Her temel işlem 1 birim sayılır (RAM modeli). En kötü durum: hedef dizide yok.
  • 3n + 3'teki 3 katsayısı ve +3 makineye göre değişir; değişmeyen şey n ile doğrusal büyümedir → T(n) = Θ(n).

Karmaşıklık Kavramı · Kodu adım adım çalıştır

dogrusalArama: Adımları Sayarak İzle

a407122ihedef = 5i = 01i < a.length1a[i] == hedef0i++0return -10toplam adım2

a = [4, 7, 2], hedef = 5 (dizide yok: en kötü durum). i = 0 atanır ve 0 < 3 denetlenir: 2 adım.

a407122ihedef = 5i = 01i < a.length1a[i] == hedef1i++0return -10toplam adım3

a[0] == hedef? 4 ≠ 5. Karşılaştırma sayısı 1 oldu.

a407122ihedef = 5i = 01i < a.length2a[i] == hedef1i++1return -10toplam adım5

i++ → i = 1, sonra 1 < 3 denetlenir: döngü sürer.

a407122ihedef = 5i = 01i < a.length2a[i] == hedef2i++1return -10toplam adım6

a[1] == hedef? 7 ≠ 5. Karşılaştırma sayısı 2 oldu.

a407122ihedef = 5i = 01i < a.length3a[i] == hedef2i++2return -10toplam adım8

i++ → i = 2, sonra 2 < 3 denetlenir: döngü sürer.

a407122ihedef = 5i = 01i < a.length3a[i] == hedef3i++2return -10toplam adım9

a[2] == hedef? 2 ≠ 5. Karşılaştırma sayısı 3 oldu.

a407122i = 3hedef = 5i = 01i < a.length4a[i] == hedef3i++3return -10toplam adım11

i++ → i = 3. 3 < 3 yanlış: koşul n + 1 = 4. kez denetlendi, döngü biter.

a407122i = 3hedef = 5i = 01i < a.length4a[i] == hedef3i++3return -11toplam adım12

return -1. Toplam 12 adım = 3n + 3 (n = 3). Her öğe için sabit sayıda (3) işlem: Θ(n).

for (int i = 0; i < a.length; i++) {
  if (a[i] == hedef)
    return i;
}
return -1;

Karmaşıklık Kavramı

En İyi, En Kötü ve Ortalama Durum

En iyi durum (best case)En elverişli girdide en az adım. Bir alt sınır verir; tek başına pek bilgi taşımaz.
En kötü durum (worst case)Her girdi için geçerli bir garanti: algoritma bundan uzun sürmez.
Ortalama durum (average case)Girdilerin bir olasılık dağılımı üzerinden beklenen adım sayısı.
703192438415hedef 7 → 1 karşılaştırma

En iyi durum: hedef ilk öğedir, tek karşılaştırma yeterlidir → Θ(1).

703192438415hedef 5 → 6 karşılaştırma, bulunamadı

En kötü durum: hedef dizide yok (ya da en sonda); n = 6 karşılaştırma → Θ(n).

703192438415hedef 4 → 4 karşılaştırma

Ortalama durum: hedef her konumda eşit olasılıkla ise ortalama (1 + 2 + … + n)/n = (n + 1)/2 = 3,5 karşılaştırma → yine Θ(n).

Karmaşıklık Kavramı

Alan Karmaşıklığı

Alan karmaşıklığı genellikle ek bellek (auxiliary space) için verilir: girdinin kendisi sayılmaz. Özyinelemede her açık çağrı yığında bir çerçeve (stack frame) tutar.

KodEk bellekBellekZaman
f1: tek döngüyalnızca x ve iΘ(1)Θ(n)
new int[n] oluşturmakn öğeli yardımcı diziΘ(n)Θ(n)
f3: f3(n−1) + f3(n−1)yığın derinliği n (aynı anda en çok n çerçeve)Θ(n)Θ(2ⁿ)
f4: f4(n/2) + f4(n/2)yığın derinliği ≈ log₂ nΘ(log n)Θ(n)
Birleştirme sıralamasıbirleştirme için yardımcı diziΘ(n)Θ(n log n)
Zaman ve bellek farklı büyüyebilir. f3 üstel sayıda çağrı yapar, ama çağrılar sırayla bittiği için yığında aynı anda en çok n çerçeve bulunur.

Asimptotik Gösterim

Büyük O (Big-O) Gösterimi

f(n) = O(g(n)) ⇔ ∃ c > 0, n₀ :
0 ≤ f(n) ≤ c · g(n), her n ≥ n₀ için
  • Büyük n'ler için f, g'nin bir sabit katını aşmaz: g bir üst sınırdır.
  • Küçük n'ler (n < n₀) önemsizdir; sabit çarpanlar c'ye gömülür.
  • Örnek: 3n² + 5n + 2 ≤ 4n², her n ≥ 6 için → O(n²).
02468100100200300400nn₀ = 6f(n)4n²
"Büyük O en kötü durumu temsil eder" ifadesi tam doğru değildir. Büyük O bir üst sınır türüdür; en kötü, en iyi ya da ortalama durumun her biri için kullanılabilir. Genellikle en kötü durum süresi için verildiğinden bu ikisi karıştırılır.

Asimptotik Gösterim

Büyük Omega (Ω) ve Büyük Teta (Θ)

GösterimAnlamıTanım (∃ c, n₀ > 0, her n ≥ n₀ için)Benzetme
f = O(g)üst sınırf(n) ≤ c · g(n)f ≤ g
f = Ω(g)alt sınırf(n) ≥ c · g(n)f ≥ g
f = Θ(g)sıkı (kesin) sınırc₁ · g(n) ≤ f(n) ≤ c₂ · g(n)f = g
  • f = Θ(g) ⇔ f = O(g) ve f = Ω(g).
  • 3n² + 5n + 2 hem O(n²) hem O(n³)'tür; ama yalnızca n² için Θ'dır.
  • Doğrusal arama: en kötü durum Θ(n), en iyi durum Θ(1); tüm girdiler için O(n) ve Ω(1).
  • Durum (hangi girdi) ile sınır (O, Ω, Θ) ayrı kavramlardır. Eklemeli sıralama en kötü Θ(n²), en iyi Θ(n): tüm girdiler için tek bir Θ yazılamaz. Birleştirme sıralaması ise her girdide Θ(n log n)'dir.
02468100100200300400nn₀ = 6f(n)4n²3n²

Asimptotik Gösterim

Örnek: 3n² + 5n + 2 = Θ(n²)

Üst sınır: 3n² + 5n + 2 ≤ c₂ n²

c₂ = 4 deneyelim: 3n² + 5n + 2 ≤ 4n² ⇔ n² − 5n − 2 ≥ 0 ⇔ n ≥ 5,37. Demek ki n₀ = 6.

Kontrol: n = 5 → 102 > 100 ✗
n = 6 → 140 ≤ 144 ✓

n = 5'te eşitsizlik bozulur, n = 6'dan itibaren sağlanır (sol taraf 6n + 8 artar, sağ taraf 8n + 4 artar).

Alt sınır: 3n² + 5n + 2 ≥ 3n²

c₁ = 3 seçilirse eşitsizlik her n ≥ 1 için doğrudur, çünkü 5n + 2 > 0.

3n² ≤ f(n) ≤ 4n², n ≥ 6

c₁ = 3, c₂ = 4, n₀ = 6 ile tanım sağlanır: f(n) = Θ(n²). Sabitler tek değildir; c₂ = 10, n₀ = 1 de çalışır.

02468100100200300400nn₀ = 6f(n)4n²3n²

Asimptotik Gösterim

Asimptotik Hesap Kuralları

Sabit çarpanları atc · f(n) = Θ(f(n)): 5n = Θ(n), n²/3 = Θ(n²).
Düşük dereceli terimleri atPolinomda en büyük derece kalır: 4n³ + 100n² + 7 = Θ(n³).
Toplam kuralı (ardışık kod)O(f) + O(g) = O(max(f, g)): Θ(n) döngü + Θ(n²) döngü = Θ(n²).
Çarpım kuralı (iç içe kod)n kez çalışan döngü içinde O(g) iş: O(n · g). İç işin her turda aynı olup olmadığına bakılır.
Logaritma tabanı önemsizloga n = logb n / logb a, sabit çarpan farkı: O(log₂ n) = O(log₁₀ n) = O(log n).
Üslü ifadelerde taban önemli3ⁿ = O(2ⁿ) yanlıştır, çünkü 3ⁿ/2ⁿ = 1,5ⁿ → ∞. Logaritmanın aksine üstel tabanlar sabit çarpanla değişmez.
Büyüme sırası: 1 < log n < √n < n < n log n < n² < n³ < 2ⁿ < n!

Asimptotik Gösterim

Yaygın Büyüme Sınıfları

SınıfAdıTipik örnekn iki katına çıkıncaBu bölümde
O(1)Sabitilk öğeyi yazdırma, dizi erişimideğişmez—
O(log n)Logaritmikikili arama, hızlı üs alma, Öklid+1 adımf6 (üst sınır)
O(√n)Karekökasallık testi (deneme bölmesi)≈ 1,41 katı—
O(n)Doğrusaldoğrusal arama, en büyük öğe, dizinin toplamı2 katıf1, f4
O(n log n)Log-doğrusalbirleştirme sıralaması, heap sort, hızlı sıralama (ortalama)2 katından biraz fazlaf5
O(n²)Kareselkabarcık, seçimli, eklemeli sıralama4 katı—
O(n³)Kübikklasik matris çarpımı8 katıf2
O(2ⁿ)Üsteltüm alt kümeler, saf özyinelemeli Fibonaccikaresi alınırf3
O(n!)Faktöriyeltüm permütasyonlarçok daha hızlı patlar—

Sınıflar yukarıdan aşağı yavaşlar. Polinom sınıflar (nk) genelde "verimli", üstel olanlar "verimsiz" sayılır. f6'nın gerçek sınıfı log n'den de yavaş büyüyen log* n'dir.

Asimptotik Gösterim

Büyüme Eğrileri

051015200255075100nadımlog₂ nnn log₂ nn²2ⁿ
  • Küçük n'de eğriler birbirine yakındır; n = 4'te n² ile 2ⁿ eşittir (16).
  • 2ⁿ n ≈ 6,6'da, n² n = 10'dan sonra 100 adımı aşar.
  • n log n doğrusala yakın kalır; log n neredeyse düzdür.
  • Uçlar daha da ayrılır: n = 10'da n! 3,6 milyonu bulur; √n ise n = 100'de yalnızca 10'dur.
  • Asimptotik analiz, eğrilerin büyük n'deki sıralamasıyla ilgilenir.

Asimptotik Gösterim

Sayılarla Büyüme: Hesaplayıcı

f(n)işlem sayısı10⁹ işlem/s ile sürebağıl

"n × 2" ile n sütunu 2, n² 4, n³ 8 katına çıkar; log₂ n yalnızca 1 artar, 2ⁿ karesini alır. Daha hızlı bilgisayar sabit bir çarpan kazandırır, daha iyi algoritma büyüme sınıfını değiştirir.

Döngü Analizi

f1: Tek Döngü → O(n)

public int f1(int n) {
  int x = 0;
  for (int i = 0; i < n; i++) {
    x++;
  }
  return x;
}
  • İlklendirme: int x = 0; x'e 0 atar; sabit zamanlı işlem, O(1).
  • Döngü: for (int i = 0; i < n; i++) i, 0'dan n − 1'e kadar ilerler: n kez çalışır.
  • Artırma: x++; her döngü adımında bir kez çalışır; O(1).
T(n) = O(1) + n · O(1) = O(n)
Döngü n kez çalışır ve gövdesi sabit zamanlıdır; toplam zaman karmaşıklığı Θ(n) olur. Fonksiyon x = n döndürür, yani dönüş değeri adım sayısının kendisidir: f1(16) = 16, f1(32) = 32.

Döngü Analizi

f1(4): Kodu Adım Adım İzle

i=0i=1i=2i=3x++ sayısı: 0

x sıfırlanır. Henüz döngü başlamadı.

i=0i=1i=2i=3x++ sayısı: 0

i = 0: koşul 0 < 4 doğru → gövdeye girilir.

0i=0i=1i=2i=3x++ sayısı: 1

x++ → x = 1. Bu, 1. döngü adımı.

0i=0i=1i=2i=3x++ sayısı: 1

i = 1: koşul 1 < 4 doğru → gövdeye girilir.

0i=01i=1i=2i=3x++ sayısı: 2

x++ → x = 2. Bu, 2. döngü adımı.

0i=01i=1i=2i=3x++ sayısı: 2

i = 2: koşul 2 < 4 doğru → gövdeye girilir.

0i=01i=12i=2i=3x++ sayısı: 3

x++ → x = 3. Bu, 3. döngü adımı.

0i=01i=12i=2i=3x++ sayısı: 3

i = 3: koşul 3 < 4 doğru → gövdeye girilir.

0i=01i=12i=23i=3x++ sayısı: 4

x++ → x = 4. Bu, 4. döngü adımı.

0i=01i=12i=23i=3x++ sayısı: 4

i = 4: koşul 4 < 4 yanlış → döngü biter. Koşul n + 1 = 5 kez denetlendi.

0i=01i=12i=23i=3x++ sayısı: 4

return x → 4. Gövde tam n = 4 kez çalıştı: Θ(n).

public int f1(int n) {
  int x = 0;
  for (int i = 0; i < n; i++) {
    x++;
  }
  return x;
}

Döngü Analizi

f2: İç İçe Döngü → O(n³)

public int f2(int n) {
  int x = 0;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < i * i; j++) {
      x++;
    }
  }
  return x;
}
  • İlklendirme: int x = 0; sabit zamanlı, O(1).
  • Dış döngü: i, 0'dan n − 1'e kadar: n kez çalışır.
  • İç döngü: j, 0'dan i · i − 1'e kadar: i² kez çalışır.
  • İç döngünün tur sayısı i'nin güncel değerine bağlıdır; bu yüzden basitçe "n · n" denemez, tur sayılarını toplamak gerekir.
Tuzak: İç içe iki döngü görünce otomatik olarak O(n²) demek yanlıştır. Burada iç döngünün sınırı i² olduğundan sonuç n³ mertebesindedir.

Döngü Analizi · Kodu adım adım çalıştır

f2(4): Kodu Adım Adım İzle

i=00 turi=11 turi=24 turi=39 turx = 0

f2(4) çağrıldı, x = 0. Gri kutular iç döngünün yapacağı turlardır: i. satırda i² kutu.

i=00 turi=11 turi=24 turi=39 turx = 0

i = 0: iç döngü koşulu 0 < 0 · 0 hemen yanlış; iç döngü hiç çalışmaz.

i=00 turi=11 turi=24 turi=39 turx = 1

i = 1: iç döngü j < 1·1 = 1 olduğu sürece döner. İlk tur (j = 0): x = 1.

i=00 turi=11 turi=24 turi=39 turx = 2

i = 2: iç döngü j < 2·2 = 4 olduğu sürece döner. İlk tur (j = 0): x = 2.

i=00 turi=11 turi=24 turi=39 turx = 5

j = 3 son tur: i = 2 satırı 4 turda bitti, x = 5.

i=00 turi=11 turi=24 turi=39 turx = 6

i = 3: iç döngü j < 3·3 = 9 olduğu sürece döner. İlk tur (j = 0): x = 6.

i=00 turi=11 turi=24 turi=39 turx = 14

j = 8 son tur: i = 3 satırı 9 turda bitti, x = 14.

i=00 turi=11 turi=24 turi=39 turx = 14

i = 4: 4 < 4 yanlış, dış döngü biter. Turlar 0 + 1 + 4 + 9.

i=00 turi=11 turi=24 turi=39 turx = 14

return 14 = 0² + 1² + 2² + 3² = Σ i². Satırlar i² uzadığı için toplam ≈ n³/3 büyür: Θ(n³).

public int f2(int n) {
  int x = 0;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < i * i; j++) {
      x++;
    }
  }
  return x;
}

Döngü Analizi

f2(5): İç Döngü Kaç Kez Çalışır?

Her çubuk, dış döngünün bir turunda (sabit i) iç döngünün kaç kez çalıştığını gösterir. Çubukların toplam alanı f2'nin yaptığı x++ sayısıdır.

0² = 0i=0i=1i=2i=3i=4toplam x++ = 0

i = 0 iken iç döngü 0 kez çalışır (0 × 0 = 0).

0² = 0i=01² = 1i=1i=2i=3i=4toplam x++ = 1

i = 1 iken iç döngü 1 kez çalışır (1 × 1 = 1).

0² = 0i=01² = 1i=12² = 4i=2i=3i=4toplam x++ = 5

i = 2 iken iç döngü 4 kez çalışır (2 × 2 = 4).

0² = 0i=01² = 1i=12² = 4i=23² = 9i=3i=4toplam x++ = 14

i = 3 iken iç döngü 9 kez çalışır (3 × 3 = 9).

0² = 0i=01² = 1i=12² = 4i=23² = 9i=34² = 16i=4toplam x++ = 30

i = 4 iken iç döngü 16 kez çalışır. Genel olarak her i için iç döngü i² kez çalışır.

0² = 0i=01² = 1i=12² = 4i=23² = 9i=34² = 16i=4toplam x++ = 30

Toplam: 0 + 1 + 4 + 9 + 16 = 30 = (n − 1) · n · (2n − 1) / 6 = 4 · 5 · 9 / 6. f2(5) = 30 döner.

Döngü Analizi

f2: Toplamı Hesaplamak

İç döngünün toplam tur sayısı (i = 0'dan n − 1'e):

Σi=0n−1 i² = (n − 1) · n · (2n − 1) / 6
= (2n³ − 3n² + n) / 6 ≈ n³ / 3

Baskın terim n³/3'tür; sabit 1/3 ve düşük dereceli terimler atılır: T(n) = Θ(n³).

nf2(n)n³/3
41421
53042
161 2401 365
3210 41610 923
Kontrol: n iki katına çıkınca (16 → 32) adım sayısı 10 416 / 1 240 ≈ 8,4 katına çıkar; 2³ = 8'e yakındır. Kübik büyümenin işareti budur.

Döngü Analizi

Döngü Kalıpları ve Toplam Formülleri

KalıpTur sayısıSonuç
for (i = 0; i < n; i++)Σ 1 = nΘ(n)
for i < n içinde for (j = 0; j < n; j++)n · nΘ(n²)
for i < n içinde for (j = 0; j < i; j++)Σ i = n(n − 1)/2Θ(n²)
for i < n içinde for (j = 0; j < i * i; j++)Σ i² = (n − 1)n(2n − 1)/6Θ(n³)
for (i = 1; i < n; i *= 2)⌈log₂ n⌉Θ(log n)
for (i = n; i > 0; i /= 2) içinde for j < nn · (⌊log₂ n⌋ + 1)Θ(n log n)
for (i = 1; i < n; i *= 2) içinde for j < i1 + 2 + 4 + … < 2nΘ(n)
for (i = 0; i < n; i = 1 << i) (f6)log* n + 1 kadarΘ(log* n)

Yöntem: her dış tur için iç döngünün tur sayısı yazılır, sonra bunlar toplanır. Toplam bilinen bir seriye (aritmetik, kareler, geometrik) indirgenir.

Döngü Analizi

f6: Kaydırmalı Döngü

public static int f6(int n) {
  int x = 0;
  // 1 << i, 2^i ile aynıdır (taşma yok sayılır)
  for (int i = 0; i < n; i = 1 << i) {
    x++;
  }
  return x;
}
  • İlklendirme: int i = 0; i'ye 0 atar; sabit zamanlı, O(1).
  • Koşul: i < n her turda i'nin n'den küçük olduğunu denetler.
  • Güncelleme: i = 1 << i 1'i i bit sola kaydırır; sonuç 2i'dir ve sabit zamanda hesaplanır.
  • Güncelleme i = 2 * i değil, i = 2^i'dir. i'nin kendisi üs olur; bu da i'yi çok daha hızlı büyütür.

Döngü Analizi

f6(20): Kodu Adım Adım İzle

??????i değerleri (n = 20); i ← 1 << i

x sıfırlanır.

0?????i değerleri (n = 20); i ← 1 << ikoşul: 0 < 20 → doğru

i = 0 ile başlanır; koşul 0 < 20 doğru.

0?????i değerleri (n = 20); i ← 1 << ikoşul: 0 < 20 → doğru

x++ → x = 1.

01????i değerleri (n = 20); i ← 1 << ikoşul: 1 < 20 → doğru

i = 1 << 0 = 1; koşul 1 < 20 doğru.

01????i değerleri (n = 20); i ← 1 << ikoşul: 1 < 20 → doğru

x++ → x = 2.

012???i değerleri (n = 20); i ← 1 << ikoşul: 2 < 20 → doğru

i = 1 << 1 = 2; koşul 2 < 20 doğru.

012???i değerleri (n = 20); i ← 1 << ikoşul: 2 < 20 → doğru

x++ → x = 3.

0124??i değerleri (n = 20); i ← 1 << ikoşul: 4 < 20 → doğru

i = 1 << 2 = 4; koşul 4 < 20 doğru.

0124??i değerleri (n = 20); i ← 1 << ikoşul: 4 < 20 → doğru

x++ → x = 4.

012416?i değerleri (n = 20); i ← 1 << ikoşul: 16 < 20 → doğru

i = 1 << 4 = 16; koşul 16 < 20 doğru.

012416?i değerleri (n = 20); i ← 1 << ikoşul: 16 < 20 → doğru

x++ → x = 5.

01241665536i değerleri (n = 20); i ← 1 << ikoşul: 65536 < 20 → yanlış, döngü biter

i = 1 << 16 = 65536; koşul 65536 < 20 yanlış → döngü biter.

01241665536i değerleri (n = 20); i ← 1 << ikoşul: 65536 < 20 → yanlış, döngü biter

return x → 5. i değerleri 0, 1, 2, 4, 16: yalnızca 5 tur.

public static int f6(int n) {
  int x = 0;
  // 1 << i == 2^i
  for (int i = 0; i < n; i = 1 << i) {
    x++;
  }
  return x;
}

Döngü Analizi

f6: Gerçekte Kaç Tur Döner?

i değerleri: 0 → 2⁰ = 1 → 2¹ = 2 → 2² = 4 → 2⁴ = 16 → 2¹⁶ = 65536. Her tur i'yi üs yapar (2'nin kuvvet kulesi).

Sık görülen akıl yürütme: "k adım sonra 2ᵏ ≥ n, öyleyse k ≥ log₂ n" — bu, i = 2 * i döngüsü için doğrudur. f6'da ise k tur sonra i, k − 1 katlı bir kule olur; tur sayısı log* n (yinelenmiş logaritma) kadardır.

O(log n) bir üst sınır olarak doğrudur, ama sıkı değildir: Θ(log* n).

nf6(n)⌈log₂ n⌉
432
1644
3255
1000510
65536516
Java'da tuzak: int kaydırma miktarı 32'ye göre mod alınır: 1 << 65536 = 1. Bu yüzden n > 65536 için i 1, 2, 4, 16, 65536 döngüsüne girer ve f6 hiç bitmez. "Taşmayı yok say" varsayımı burada önemlidir.

Özyinelemeli Analiz

Yineleme Bağıntısı (Recurrence)

Özyinelemeli bir fonksiyonun süresi, kendi daha küçük girdilerdeki süresi cinsinden yazılır:

T(n) = (alt çağrıların süreleri) + (çağrı dışında yapılan iş),   T(taban) = Θ(1)
Açma (yerine koyma)Bağıntıyı kendi içine tekrar tekrar koyup bir örüntü bulmak; taban duruma ulaşınca toplamak. (f3)
Özyineleme ağacıHer çağrıyı bir düğüm olarak çizip her düzeydeki işi toplamak. (f3, f4, f5)
Ana TeoremT(n) = aT(n/b) + f(n) biçimindeki böl-ve-fethet bağıntılarını doğrudan çözmek. (f4, f5)
T(n)+ f(n): çağrı dışı işT(n/b)T(n/b)T(n/b)…a çağrı, her biri n/b boyutlu (ya da n − 1)
Bağıntı kurarken sorular: Kaç özyinelemeli çağrı var? Her çağrının girdisi ne kadar küçülüyor (n − 1 mi, n/2 mi)? Çağrılar dışında ne kadar iş yapılıyor?

Özyinelemeli Analiz

f3: İki Çağrı, n − 1 → O(2ⁿ)

public long f3(int n) {
  if (n <= 1) {
    return 1;
  }
  return f3(n - 1) + f3(n - 1);
}
  • Taban durum (base case): n ≤ 1 iken 1 döner; sabit zamanlı, O(1).
  • Özyinelemeli durum (recursive case): n > 1 iken iki kez f3(n − 1) çağrılır ve sonuçlar toplanır (sabit iş c).
T(n) = 2T(n − 1) + c,   n > 1     T(1) = c
f3(4)1 çağrıf3(3)2 çağrıf3(2)4 çağrıf3(1)8 çağrıgirdi 1 azalır, çağrı sayısı 2 katına çıkar: 1 + 2 + 4 + 8 = 15 = 2⁴ − 1
Girdi her çağrıda yalnızca 1 azalır ama çağrı sayısı her düzeyde ikiye katlanır. Bu bağıntı T(n/b) biçiminde olmadığı için Ana Teorem uygulanamaz; açma yöntemiyle çözülür.

Özyinelemeli Analiz

f3(3): Çağrıları Adım Adım İzle

f3(3)f3(2)f3(2)f3(1)f3(1)f3(1)f3(1)

f3(3) çağrıldı: 3 > 1, taban durum değil.

f3(3)f3(2)f3(2)f3(1)f3(1)f3(1)f3(1)

Satır 5: ilk f3(2) çağrısı. f3(3) yığında bekliyor.

f3(3)f3(2)f3(2)f3(1)= 1f3(1)f3(1)f3(1)

f3(1): n ≤ 1 → taban durum, 1 döner.

f3(3)f3(2)f3(2)f3(1)= 1f3(1)= 1f3(1)f3(1)

f3(2) ikinci çağrısını yapar: yine f3(1) = 1.

f3(3)f3(2)= 2f3(2)f3(1)= 1f3(1)= 1f3(1)f3(1)

f3(2) = 1 + 1 = 2 döner. Sol alt ağaç bitti.

f3(3)f3(2)= 2f3(2)f3(1)= 1f3(1)= 1f3(1)f3(1)

f3(3), ikinci f3(2)'yi çağırır: aynı iş baştan yapılır.

f3(3)f3(2)= 2f3(2)f3(1)= 1f3(1)= 1f3(1)= 1f3(1)

f3(1) = 1.

f3(3)f3(2)= 2f3(2)f3(1)= 1f3(1)= 1f3(1)= 1f3(1)= 1

f3(1) = 1.

f3(3)f3(2)= 2f3(2)= 2f3(1)= 1f3(1)= 1f3(1)= 1f3(1)= 1

İkinci f3(2) = 2 döner.

f3(3)= 4f3(2)= 2f3(2)= 2f3(1)= 1f3(1)= 1f3(1)= 1f3(1)= 1

f3(3) = 2 + 2 = 4 döner. Toplam 7 = 2³ − 1 çağrı; yığın derinliği en çok 3.

public long f3(int n) {
  if (n <= 1) {
    return 1;
  }
  return f3(n - 1) + f3(n - 1);
}

Özyinelemeli Analiz

f3: Bağıntıyı Açma

T(n) = 2T(n − 1) + c

Bağıntının kendisi: iki alt çağrı, sabit ek iş.

= 2[2T(n − 2) + c] + c = 4T(n − 2) + 3c

T(n − 1) yerine kendi tanımını koyarız.

= 8T(n − 3) + 7c

Bir kez daha açınca örüntü belirir: katsayılar 2, 4, 8 …

= 2ᵏ T(n − k) + (2ᵏ − 1)c

k adım sonra genel biçim. Ek iş (c) ihmal edilirse T(n) = 2ᵏ T(n − k) yazılır; büyüme sınıfı değişmez.

k = n − 1: T(n) = 2ⁿ⁻¹c + (2ⁿ⁻¹ − 1)c = (2ⁿ − 1)c

Taban durum T(1) = c'ye n − k = 1 iken ulaşılır. Sonuç: T(n) = Θ(2ⁿ).

4332222111111111 · c2 · c4 · c8 · c

Java ile sayıldığında: f3(16) 65 535, f3(32) 4 294 967 295 çağrı yapar (2ⁿ − 1).

Ana Teorem

Ana Teorem: Genel Biçim

Böl ve fethet (divide and conquer) algoritmalarının bağıntılarını doğrudan çözmek için kullanılır:

T(n) = a · T(n/b) + f(n),   a ≥ 1, b > 1

a: alt problem (çağrı) sayısı · b: küçülme oranı, alt problem boyutu n/b · f(n): bölme ve birleştirme işi. Derinlik logb n, yaprak sayısı alogb n = nlogb a.

f(n)f(n/b)f(n/b)…f(n/b)a çocuk· ·· ·· ·⋮⋮Θ(1)Θ(1)Θ(1)Θ(1)Θ(1)Θ(1)Θ(1)Θ(1)…f(n)a · f(n/b)a² · f(n/b²)nlog b a · Θ(1)derinlik: logb n

Ana Teorem

Ana Teorem: Üç Durum

f(n), yaprakların toplam işi olan nlogb a ile karşılaştırılır. c = f(n)'nin polinom derecesi:

DurumKoşulSonuçYorum
1f(n) = O(nc), c < logb aT(n) = Θ(nlogb a)yapraklar baskın
2f(n) = Θ(nc), c = logb aT(n) = Θ(nlogb a · log n)düzeyler dengeli
3f(n) = Ω(nc), c > logb a ve a · f(n/b) ≤ k · f(n), k < 1T(n) = Θ(f(n))kök baskın
Üç durumda da yalnızca f(n) = O(nᶜ) yazmak yetmez. Örneğin f(n) = 1 de O(n²)'dir, ama T(n) = O(1) olamaz. Bu yüzden Durum 2'de f = Θ(nᶜ), Durum 3'te f = Ω(nᶜ) ve düzenlilik koşulu istenir; sonuçlar Θ ile sıkıdır.

Düzenlilik koşulu (regularity), f(n) = nᶜ gibi polinomlar için kendiliğinden sağlanır: a(n/b)ᶜ = (a/bᶜ) nᶜ ve a/bᶜ < 1.

Ana Teorem

Neden Üç Durum? Düzey Toplamları

f(n) = nᶜ ise ağacın j. düzeyinde aʲ düğüm, her biri (n/bʲ)ᶜ iş yapar: düzey toplamı = nᶜ · (a/bᶜ)ʲ. Toplam, oranı r = a/bᶜ olan bir geometrik seridir.

4T(n/2) + nj=0j=1j=2j=3r = 2 > 1: artar

Durum 1: son düzey (yapraklar) baskın → Θ(n²)

2T(n/2) + nj=0j=1j=2j=3r = 1: sabit

Durum 2: log n düzey × n iş → Θ(n log n)

2T(n/2) + n²j=0j=1j=2j=3r = 1/2 < 1: azalır

Durum 3: kök baskın → Θ(n²)

r > 1 ⇔ bᶜ < a ⇔ c < logb a. Yani Ana Teoremin üç durumu, geometrik serinin artan, sabit ya da azalan olmasına karşılık gelir.

Ana Teorem

Örnek: T(n) = 2T(n/2) + O(n)

a = 2,   b = 2,   f(n) = O(n)

Parametreleri okuyalım: iki alt problem, her biri n/2 boyutunda, doğrusal birleştirme işi.

logb a = log₂ 2 = 1

Yaprak işinin üssü 1'dir: nlog₂ 2 = n.

f(n) = Θ(n¹) → c = 1

f(n)'nin derecesi c = 1.

c = logb a → Durum 2

Üsler eşit: her düzey aynı (n) işi yapar.

T(n) = Θ(n log n)

Durum 2: T(n) = Θ(nlogb a · log n) = Θ(n log n).

Bu bağıntı nerede çıkar?
  • Birleştirme sıralaması (merge sort): diziyi ikiye böl, iki yarıyı sırala, Θ(n)'de birleştir.
  • Bölümdeki f5 fonksiyonu: f1(n) + iki f5(n/2) çağrısı.
  • Hızlı sıralamanın (quicksort) dengeli bölme durumu.

Ana Teorem

Ana Teorem: Örnekler

Bağıntıa, blogb acDurumSonuçAlgoritma
T(n/2) + 11, 2002Θ(log n)ikili arama
2T(n/2) + 12, 2101Θ(n)f4, ağaç gezme
2T(n/2) + n2, 2112Θ(n log n)f5, birleştirme sır.
3T(n/2) + n3, 2≈ 1,58511Θ(n1,585)Karatsuba çarpma
4T(n/2) + n4, 2211Θ(n²)—
7T(n/2) + n²7, 2≈ 2,80721Θ(n2,807)Strassen
2T(n/2) + n²2, 2123Θ(n²)—
T(n/2) + n1, 2013Θ(n)hızlı seçme (ortalama)

Durum 3 satırlarında düzenlilik: 2(n/2)² = n²/2 ≤ ½ n² ve 1 · (n/2) ≤ ½ n, k = ½ ile sağlanır.

Ana Teorem

Ana Teorem Ne Zaman Uygulanamaz?

Çıkarmalı bağıntılarT(n) = 2T(n − 1) + c (f3) ya da T(n) = T(n − 1) + n: alt problem n/b değil, n − 1. Açma yöntemi kullanılır.
Polinom olmayan farkT(n) = 2T(n/2) + n / log n: f(n), n'den yalnızca log çarpanı kadar küçük; hiçbir duruma girmez.
Eşit olmayan bölmeT(n) = T(n/3) + T(2n/3) + n: alt problemler farklı boyutta. Özyineleme ağacı (ya da Akra–Bazzi) ile Θ(n log n).
Sabit olmayan a ya da a < 1T(n) = 2ⁿ T(n/2) + n ya da T(n) = ½ T(n/2) + n: teoremin a ≥ 1 sabit varsayımı bozulur.
Temel biçimin bir genişlemesi: f(n) = Θ(nlogb a · logᵏ n) ise T(n) = Θ(nlogb a · logᵏ⁺¹ n). Örneğin T(n) = 2T(n/2) + n log n = Θ(n log² n).

Uygulama: f4 ve f5

f4: İki Çağrı, n/2 → O(n)

public int f4(int n) {
  if (n <= 1) {
    return 1;
  }
  return f4(n / 2) + f4(n / 2);
}
  • Taban durum: n ≤ 1 iken 1 döner; O(1).
  • Özyinelemeli durum: n > 1 iken iki kez f4(n/2) çağrılır, sonuçlar toplanır (sabit iş).
T(n) = 2T(n/2) + O(1),   T(1) = O(1)
n = 81 çağrın = 42 çağrın = 24 çağrın = 18 çağrıgirdi yarıya iner: yalnızca log₂ 8 + 1 = 4 düzey, 1 + 2 + 4 + 8 = 15 = 2n − 1 çağrı
f3 ile tek fark girdinin n − 1 yerine n/2 olmasıdır; ama bu, sonucu Θ(2ⁿ)'den Θ(n)'ye indirir. İki çağrı her zaman üstel süre demek değildir: girdinin ne kadar küçüldüğü belirleyicidir.

Uygulama: f4 ve f5

f4(8): Özyineleme Ağacı

8442222111111111 · c

Kök: f4(8) yalnızca sabit iş (c) yapar ve iki çağrı başlatır.

8442222111111111 · c2 · c

Düzey 1: iki f4(4) çağrısı, toplam 2c.

8442222111111111 · c2 · c4 · c

Düzey 2: dört f4(2) çağrısı, toplam 4c. Düzey işi her adımda ikiye katlanıyor.

8442222111111111 · c2 · c4 · c8 · c

Yapraklar: sekiz f4(1), toplam 8c = n · c. Toplam c(1 + 2 + 4 + 8) = 15c = (2n − 1)c → Θ(n).

Düzey toplamları geometrik olarak artar; toplamı son terim (yapraklar) belirler. Java ile: f4(16) 31, f4(32) 63 çağrı yapar (2n − 1).

Uygulama: f4 ve f5

f4: Ana Teorem ile Çözüm

T(n) = 2T(n/2) + O(1)

Genel biçim T(n) = aT(n/b) + f(n) ile eşleştirelim.

a = 2, b = 2, f(n) = O(1)

Örnekte a = 2, b = 2, f(n) = O(1).

logb a = log₂ 2 = 1

Yaprak işi nlog₂ 2 = n¹ = n.

f(n) = O(n⁰) → c = 0 < 1

f(n) = O(1), c = 0'a karşılık gelir; c, logb a = 1'den küçüktür.

Durum 1: T(n) = Θ(nlog₂ 2) = Θ(n)

Ana Teoreme göre f(n) = O(nᶜ), c < logb a ise T(n) = Θ(nlogb a). Sonuç: Θ(n).

Ağaç ile aynı sonuçÖzyineleme ağacında 2n − 1 düğüm vardı. Ana Teorem bu toplamı hesaplamadan aynı sonucu verir: yapraklar baskın.

Not: f4 için "O(log n)" demek sık yapılan bir hatadır; doğrusu Θ(n)'dir. log n, yalnızca yığın derinliğidir (bellek).

Uygulama: f4 ve f5

f5: Doğrusal İş + İki Çağrı → O(n log n)

public int f5(int n) {
  if (n <= 1) {
    return 1;
  }
  return f1(n) + f5(n / 2) + f5(n / 2);
}
  • Taban durum: n ≤ 1 iken 1 döner; O(1).
  • Özyinelemeli durum: n > 1 iken önce f1(n) çağrılır (Θ(n) iş), sonra iki kez f5(n/2).
T(n) = 2T(n/2) + f1(n) = 2T(n/2) + O(n)
f4'ten tek farkı her çağrıda yapılan doğrusal iştir. Bu, birleştirme sıralamasının bağıntısıyla aynıdır. Sonuç "O(n + log n)" değil, Θ(n log n)'dir.

Uygulama: f4 ve f5 · Kodu adım adım çalıştır

f5(4): Çağrıları Adım Adım İzle

f5(4)f5(2)f5(2)f5(1)f5(1)f5(1)f5(1)düzey işi

f5(4) çağrıldı: 4 > 1, taban durum değil.

f5(4)f1: 4f5(2)f5(2)f5(1)f5(1)f5(1)f5(1)4düzey işi

Satır 5 önce f1(4)'ü hesaplar: 4 turluk döngü, 4 birim iş. Sonra iki f5(2) çağrısı.

f5(4)f1: 4f5(2)f5(2)f5(1)f5(1)f5(1)f5(1)4düzey işi

f5(2) çağrıldı: 2 > 1, taban durum değil.

f5(4)f1: 4f5(2)f1: 2f5(2)f5(1)f5(1)f5(1)f5(1)42düzey işi

Satır 5 önce f1(2)'ü hesaplar: 2 turluk döngü, 2 birim iş. Sonra iki f5(1) çağrısı.

f5(4)f1: 4f5(2)f1: 2f5(2)f5(1)= 1f5(1)f5(1)f5(1)421düzey işi

f5(1): n ≤ 1 → taban durum, 1 döner.

f5(4)f1: 4f5(2)f1: 2f5(2)f5(1)= 1f5(1)= 1f5(1)f5(1)421 + 1düzey işi

f5(1): n ≤ 1 → taban durum, 1 döner.

f5(4)f1: 4f5(2)f1: 2 = 4f5(2)f5(1)= 1f5(1)= 1f5(1)f5(1)421 + 1düzey işi

f5(2) = f1(2) + f5(1) + f5(1) = 2 + 1 + 1 = 4 döner.

f5(4)f1: 4f5(2)f1: 2 = 4f5(2)f5(1)= 1f5(1)= 1f5(1)f5(1)421 + 1düzey işi

İkinci f5(2) çağrısı: ilkiyle aynı işi baştan yapar.

f5(4)f1: 4f5(2)f1: 2 = 4f5(2)f1: 2f5(1)= 1f5(1)= 1f5(1)f5(1)42 + 21 + 1düzey işi

Satır 5 önce f1(2)'ü hesaplar: 2 turluk döngü, 2 birim iş. Sonra iki f5(1) çağrısı.

f5(4)f1: 4f5(2)f1: 2 = 4f5(2)f1: 2f5(1)= 1f5(1)= 1f5(1)= 1f5(1)42 + 21 + 1 + 1düzey işi

f5(1): n ≤ 1 → taban durum, 1 döner.

f5(4)f1: 4f5(2)f1: 2 = 4f5(2)f1: 2f5(1)= 1f5(1)= 1f5(1)= 1f5(1)= 142 + 21 + 1 + 1 + 1düzey işi

f5(1): n ≤ 1 → taban durum, 1 döner.

f5(4)f1: 4f5(2)f1: 2 = 4f5(2)f1: 2 = 4f5(1)= 1f5(1)= 1f5(1)= 1f5(1)= 142 + 21 + 1 + 1 + 1düzey işi

f5(2) = f1(2) + f5(1) + f5(1) = 2 + 1 + 1 = 4 döner.

f5(4)f1: 4 = 12f5(2)f1: 2 = 4f5(2)f1: 2 = 4f5(1)= 1f5(1)= 1f5(1)= 1f5(1)= 142 + 21 + 1 + 1 + 1düzey işi

f5(4) = 4 + 4 + 4 = 12. Her düzeyin işi n = 4: log₂ 4 = 2 düzey · 4 + 4 yaprak → n log₂ n + n. Bağıntı 2T(n/2) + n: Θ(n log n).

public int f5(int n) {
  if (n <= 1) {
    return 1;
  }
  return f1(n) + f5(n / 2) + f5(n / 2);
}

Uygulama: f4 ve f5

f5(8): Özyineleme Ağacı

8442222111111118

Kök: f5(8) içinde f1(8) 8 adım yapar.

84422221111111184 + 4 = 8

Düzey 1: iki f5(4), her biri f1(4) = 4 adım → toplam 8.

84422221111111184 + 4 = 84 · 2 = 8

Düzey 2: dört f5(2), her biri 2 adım → yine 8. Her düzey n iş yapar.

84422221111111184 + 4 = 84 · 2 = 88 · 1 = 8

Yapraklar 8 × 1. Toplam 3 · 8 + 8 = 32 = n log₂ n + n → Θ(n log n). Java: f5(8) = 32.

log₂ n düzeyin her biri n iş yapar. Java ile: f5(16) = 80 = 16 · 4 + 16, f5(32) = 192 = 32 · 5 + 32.

Uygulama: f4 ve f5

f5: Ana Teorem ile Çözüm

T(n) = 2T(n/2) + O(n)

T(n) = aT(n/b) + f(n) biçiminde.

a = 2, b = 2, f(n) = O(n)

Parametreler f4 ile aynı, yalnızca f(n) değişti.

logb a = log₂ 2 = 1,   c = 1

f(n) = Θ(n) → c = 1 = logb a.

Durum 2: T(n) = Θ(nlogb a log n) = Θ(n log n)

Üsler eşit: Θ(n log n). Bölümün başındaki örnekle aynı bağıntı.

f4f5
Çağrı2 × n/22 × n/2
Ek iş f(n)O(1)O(n)
c vs logb a0 < 11 = 1
Durum12
SonuçΘ(n)Θ(n log n)

Karşılaştırma

f1–f6: Java ile Ölçülen Adım Sayıları

FonksiyonBağıntı / toplamn = 16n = 32OranSonuç
f1 dönüşΣ 1 = n1632× 2Θ(n)
f2 dönüşΣ i²1 24010 416× 8,4Θ(n³)
f3 çağrı2T(n − 1) + c65 5354 294 967 295× 65 537Θ(2ⁿ)
f4 çağrı2T(n/2) + c3163× 2Θ(n)
f5 dönüş2T(n/2) + n80192× 2,4Θ(n log n)
f6 dönüşi ← 2i45+ 1Θ(log* n)
n iki katına çıkınca oran, büyüme sınıfını ele verir: Θ(n) → ×2, Θ(n log n) → ×2'den biraz fazla, Θ(n³) → ×8, Θ(2ⁿ) → ×2ⁿ.

Karşılaştırma

Etkileşimli f1–f6 Adım Sayacı

FonksiyonAdım sayısıGöreli büyüklük (log ölçek)

Adım: f1, f2, f6 için x++ sayısı; f3, f4 için çağrı sayısı; f5 için çağrı + f1 döngü adımları. Değerler kodun mantığıyla hesaplanır (f3 için BigInt).

Karşılaştırma

Kısa Bakış: Amortize Analiz

  • Amortize analiz (amortized analysis), bir işlem dizisinin toplam maliyetini işlem sayısına böler.
  • Dinamik dizi: dolunca kapasite ikiye katlanır ve tüm öğeler kopyalanır (pahalı); diğer eklemeler 1 birimdir.
  • n eklemede kopyalar 1 + 2 + 4 + … < 2n → toplam < 3n → ekleme başına amortize Θ(1).
  • Ortalama durumdan farklıdır: olasılık yoktur, her işlem dizisi için garanti verir.
112233145516171899toplam = 24 · ortalama = 2,67

Kapasite 1'den başlayarak 9 ekleme; turuncu çubuklar kapasite artırma (kopyalama) içerir.

Tek bir eklemenin en kötü durumu Θ(n) olsa da, dizinin tamamı için 24 < 3 · 9 = 27 birim harcanır. Ayrıntı: toplama, hesap (accounting) ve potansiyel yöntemleri.

Özet

Özet

KonuHatırlanacaklar
Karmaşıklıkzaman = temel işlem sayısı T(n); bellek = ek bellek (yığın dahil); en iyi / en kötü / ortalama
GösterimO: üst, Ω: alt, Θ: sıkı sınır; c ve n₀ ile kanıtlanır; sabitler ve düşük terimler atılır
Döngülertur sayılarını topla: f1 Σ1 = n → Θ(n); f2 Σi² → Θ(n³); f6 i ← 2i → Θ(log* n) (O(log n) sıkı değil)
Özyinelemebağıntı kur: çağrı sayısı, küçülme biçimi, ek iş; açma veya özyineleme ağacı ile çöz
f32T(n − 1) + c = (2ⁿ − 1)c → Θ(2ⁿ); Ana Teorem uygulanamaz
Ana TeoremaT(n/b) + f(n): f(n)'yi nlogb a ile karşılaştır; yapraklar / dengeli / kök baskın
f4, f52T(n/2) + 1 → Durum 1, Θ(n); 2T(n/2) + n → Durum 2, Θ(n log n)

Özet

Etkileşimli Simülatörler

Asimptotik Büyüme Gezginilog n, n, n log n, n², n³ ve 2ⁿ'nin aynı n'de karşılaştırması; iki fonksiyonun kesişme (crossover) noktası.
Özyineleme ve Ana TeoremVerilen a, b ve f(n) = nᵏ ile T(n) = aT(n/b) + f(n) için özyineleme ağacının düzeyleri ve Ana Teorem durumu.
Büyüme HesaplayıcıVerilen bir n için 1'den n!'e kadar her fonksiyonun işlem sayısı ve saniyede 10⁹ işlem yapan bir bilgisayardaki süresi; "n × 2" ile girdiyi ikiye katlama.

Özet

Sık Yapılan Hatalar

Büyük O = en kötü durum sanmakO bir üst sınırdır; en kötü durum ise bir girdi türüdür. "En iyi durum O(1)" da geçerli bir cümledir.
Sabitleri ve küçük terimleri yazmakO(3n + 3), O(n²/3 + n) yazılmaz: O(n) ve O(n²) yeterlidir.
"İç içe döngü = n²"Belirleyici olan iç döngünün sınırıdır: f2'de i² olduğu için Θ(n³); i *= 2 döngüsü ise log n tur döner.
"İki çağrı = üstel"f3 (n − 1) Θ(2ⁿ), f4 (n/2) Θ(n)'dir. Küçülme biçimi her şeyi değiştirir.
Ana Teoremi her bağıntıya uygulamakT(n − 1) içeren, eşit bölmeyen ya da f(n) = n/log n olan bağıntılarda teorem geçerli değildir.
Durum 3'te düzenliliği unutmakc > logb a yetmez; a · f(n/b) ≤ k · f(n) (k < 1) de sağlanmalıdır.

Özet

Örnek Problemler

  1. 2n + 10 = O(n) olduğunu c ve n₀ bularak gösterin.
  2. T(n) = 3T(n/3) + n bağıntısını çözün.
  3. T(n) = 9T(n/3) + n bağıntısını çözün.
  4. T(n) = T(n/2) + n bağıntısını çözün (düzenliliği kontrol edin).
  5. for (i = 1; i < n; i *= 2) for (j = 0; j < i; j++) x++; kaç kez x++ yapar?
  6. for (i = n; i > 0; i /= 2) for (j = 0; j < n; j++) x++; karmaşıklığı nedir?
Cevapları göster
  1. 2n + 10 ≤ 3n ⇔ n ≥ 10: c = 3, n₀ = 10 (ya da c = 12, n₀ = 1).
  2. a = 3, b = 3, log₃ 3 = 1 = c → Durum 2 → Θ(n log n).
  3. log₃ 9 = 2 > c = 1 → Durum 1 → Θ(n²).
  4. log₂ 1 = 0 < c = 1; 1 · (n/2) ≤ ½ · n (k = ½) → Durum 3 → Θ(n).
  5. i = 1, 2, 4, …, 2ᵏ < n: toplam 1 + 2 + … + 2ᵏ = 2ᵏ⁺¹ − 1 < 2n → Θ(n) (n = 16: 15).
  6. Dış döngü ⌊log₂ n⌋ + 1 tur, her turda n iş → Θ(n log n).

Özet

Alıştırmalar

  1. f2'de iç döngü koşulu j < i olsaydı karmaşıklık ne olurdu? f2(5) ne döndürürdü?
  2. return g(n/2) + g(n/2) + g(n/2) + g(n/2); (taban n ≤ 1) için bağıntıyı yazıp çözün.
  3. f3'ün son satırı return 2 * f3(n - 1); olsaydı dönüş değeri ve süresi nasıl değişirdi?
  4. T(n) = 8T(n/2) + n² ve T(n) = 7T(n/2) + n² bağıntılarını çözün; hangi algoritmalara karşılık gelirler?
  5. n² ≠ O(n) olduğunu çelişki ile kanıtlayın.
  6. f6'yı for (i = 1; i < n; i *= 2) yaparsak n = 1000 için kaç tur döner? f6(1000) ile karşılaştırın.
Cevaplar / ipuçları
  1. Σ i = n(n − 1)/2 → Θ(n²); f2(5) = 0 + 1 + 2 + 3 + 4 = 10.
  2. T(n) = 4T(n/2) + c; log₂ 4 = 2 > 0 → Durum 1 → Θ(n²).
  3. Dönüş değeri aynı (2ⁿ⁻¹); ama tek çağrı: T(n) = T(n − 1) + c → Θ(n).
  4. log₂ 8 = 3 > 2 → Θ(n³) (böl-ve-fethet matris çarpımı); log₂ 7 ≈ 2,807 → Θ(n2,807) (Strassen).
  5. n² ≤ c·n, her n ≥ n₀ için olsun ⇒ n ≤ c. n = max(n₀, ⌈c⌉ + 1) seçilince çelişki.
  6. i = 1, 2, 4, …, 512 → 10 tur (⌈log₂ 1000⌉); f6(1000) ise yalnızca 5 tur döner.

Özet

Kaynaklar

  • Cormen, Leiserson, Rivest ve Stein, Introduction to Algorithms, 4. baskı, MIT Press, 2022 (Bölüm 3 ve 4).
  • Sedgewick ve Wayne, Algorithms, 4. baskı, Addison-Wesley, 2011 (Bölüm 1.4: Analysis of Algorithms).
  • Kleinberg ve Tardos, Algorithm Design, Pearson, 2005 (Bölüm 2 ve 5).
  • D. E. Knuth, "Big Omicron and Big Omega and Big Theta", SIGACT News 8(2), 1976.
  • J. L. Bentley, D. Haken ve J. B. Saxe, "A General Method for Solving Divide-and-Conquer Recurrences", SIGACT News 12(3), 1980.

Son

Bölüm 1.2: Algoritma Karmaşıklığı
Sonraki bölüm: Bölüm 2: Sıralama Algoritmaları · Terim sözlüğü
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.