Bölüm 1: Giriş ve Algoritma Analizi

C ile Veri Yapıları ve Algoritmalar · Çalışma Soruları
Algoritma ve ADTSeçimli sıralamaAdım saymaO, Ω, ΘSihirli karePerformans ölçümüÖzyinelemeli ödevler
Sercan KÜLCÜ

Çoktan Seçmeli · Temeller

Soru 1: Sonlanmayan Program

İşletim sistemi gibi kapatılana dek çalışmayı sürdüren bir program, algoritma ölçütlerinden hangisini sağlamaz?

C: Algoritma her girdide sonlu adım sonra durmalıdır. İşletim sistemi komutları kesin ve uygulanabilir olabilir, çıktı da üretir; yalnız sona ermediği için algoritma değil, bir hesaplama yöntemidir.

Çoktan Seçmeli · Temeller

Soru 2: Opak Tip

main.c yalnızca kesir.h'yi içeriyor; başlıkta typedef struct kesir Kesir; var, yapının alanları ise kesir.c'de tanımlı. main.c'deki hangi satır derlenmez?

B: main.c için struct kesir eksik (incomplete) bir türdür: işaretçisi tutulabilir, fonksiyonlara geçirilebilir, ama alanına erişilemez ve sizeof alınamaz. Alanların gizlenmesi ADT'nin C'deki karşılığıdır; erişim yalnızca arayüz fonksiyonlarıyla olur. C'deki kesir_sil(NULL) çağrısı free(NULL) yapar; bu zararsızdır.

Hata Bulma · Temeller

Soru 3: Kesir Toplama ve Sızıntı

Sunumdaki kesir gerçeklemesiyle bu parça ne yazdırır? Bellek açısından kusuru nedir, nasıl düzeltilir?

Kesir *a = kesir_olustur(1, 4);
Kesir *b = kesir_olustur(1, 6);
Kesir *t = kesir_topla(a, b);
kesir_yaz(t);
printf("%d\n",
  kesir_esit(t, kesir_olustur(5, 12)));
kesir_sil(a); kesir_sil(b);
kesir_sil(t);
Cevabı göster

Çıktı: 10/24 ve 1.

  • kesir_topla sadeleştirmez: pay 1·6 + 1·4 = 10, payda 4·6 = 24.
  • kesir_esit çapraz çarpar: 10·12 = 120 = 5·24 → 1 (eşit).
  • kesir_olustur(5, 12)'nin döndürdüğü kesir hiçbir değişkende tutulmadı, hiç free edilmedi: bellek sızıntısı. Sayaçlı sarmalayıcıyla 4 malloc, 3 free görülür.
Kesir *u = kesir_olustur(5, 12);
if (t && u)
  printf("%d\n", kesir_esit(t, u));
kesir_sil(u);

Her olustur/topla sonucu çağırana aittir; bırakmak da onun işidir.

Çoktan Seçmeli · Seçimli Sıralama

Soru 4: İki Turdan Sonra

Seçimli sıralama (sort) {5, 1, 4, 2, 3} dizisine uygulanıyor. Dış döngünün ilk iki turu (i = 0 ve i = 1) bittiğinde dizi nasıl görünür?

D: i = 0'da en küçük 1 (indis 1) bulunur, 5 ile takas edilir: {1, 5, 4, 2, 3}. i = 1'de kalan kısmın en küçüğü 2 (indis 3) bulunur, list[1] = 5 ile takas edilir: {1, 2, 4, 5, 3}. Takas yalnızca iki hücrenin yerini değiştirir; aradaki 4 yerinde kalır, A bunu kaydırma sanır.

Çıktı Sorusu · Seçimli Sıralama

Soru 5: Yan Etkili Makro Argümanı

Sunumdaki üç argümanlı SWAP makrosuyla bu parça ne yazdırır? Takas gerçekleşti mi?

#define SWAP(x, y, t) \
        ((t) = (x), (x) = (y), (y) = (t))
int a[] = {7, 8, 9}, i = 0, j = 2, t;
SWAP(a[i++], a[j], t);
printf("%d %d %d i=%d\n",
       a[0], a[1], a[2], i);
Cevabı göster

Çıktı: 7 9 7 i=2.

Önişlemci metni yerine koyar: ((t) = (a[i++]), (a[i++]) = (a[j]), (a[j]) = (t)). i++ iki kez değerlendirilir:

  • t = a[0] → 7, i = 1.
  • a[1] = a[2] → 9, i = 2.
  • a[2] = t → 7.

Virgül işleci her adımı sıraya koyduğu için sonuç tanımlıdır, ama takas yanlış hücrelerde yapıldı: 8 kayboldu. Yan etkili argüman makroya verilmez; swap(&a[i], &a[j]); i++; yazılır.

Adım Adım Çalıştırma · Seçimli Sıralama

Soru 6: Seçimli Sıralamayı İzlemek

sort({4, 2, 5, 1}, 4) çağrısında her turdan sonra dizi ne olur? Toplam kaç karşılaştırma ve kaç gerçek takas (i ≠ min) yapılır?

40215213

Başlangıç. Dış döngü n − 1 = 3 tur döner.

40215213imin

i = 0: j = 1, 2, 3 için 3 karşılaştırma. 2 < 4 → min = 1; 1 < 2 → min = 3.

40215213imin

list[0] ↔ list[3]: 1 başa gelir.

10215243i, min

i = 1: 2 karşılaştırma (5 ve 4, 2'den küçük değil). min = i kalır; SWAP hücreyi kendisiyle takas eder, gerçek takas sayılmaz.

10215243imin

i = 2: tek karşılaştırma, 4 < 5 → min = 3.

10215243imin

list[2] ↔ list[3].

10214253

i = 3 = n − 1 → döngü biter. Karşılaştırma 3 + 2 + 1 = 6 = n(n−1)/2; takas 2 (en çok n − 1).

void sort(int list[], int n) {
  int i, j, min, temp;
  for (i = 0; i < n - 1; i++) {
    min = i;
    for (j = i + 1; j < n; j++)
      if (list[j] < list[min])
        min = j;
    SWAP(list[i], list[min], temp);
  }
}

Çoktan Seçmeli · Performans Analizi

Soru 7: Adım Sayısı

Sunumdaki kurala göre (atama, her for testi, gövde ve return birer adım; bildirimler 0) aşağıdaki fonksiyon n = 7 için kaç program adımı atar?

float ort(float a[], int n) {
  float s = 0;
  int i;
  for (i = 0; i < n; i += 2)
    s += a[i];
  return s;
}

B: i = 0, 2, 4, 6 için gövde 4 kez çalışır, for testi 5 kez (son test i = 8'de yanlış) yapılır. 1 (s = 0) + 5 + 4 + 1 (return) = 11. Genel olarak 2⌈n/2⌉ + 3 adım: yine O(n). 17 = 2n + 3, döngünün ikişer arttığını gözden kaçırır.

Çoktan Seçmeli · Performans Analizi

Soru 8: rsum'un Yığın Derinliği

rsum(list, 1000) çağrıldığında en derin anda yığında kaç rsum çerçevesi aynı anda bulunur?

A: rsum(list, 1000) → rsum(list, 999) → … → rsum(list, 0): n + 1 = 1001 çağrı iç içedir ve rsum(list, 0) çalışırken hiçbiri dönmemiştir. Bu yüzden Srsum(n) n ile doğrusal büyür; döngülü sum ise tek çerçeveyle O(1) ek bellek kullanır.

Klasik Soru · Performans Analizi

Soru 9: İki Katına Çıkan Sayaç

Aşağıdaki parçada x++ n = 16 ve n = 20 için kaç kez işletilir? Parçanın zaman karmaşıklığı nedir?

x = 0;
for (i = 1; i <= n; i *= 2)
  for (j = 0; j < i; j++)
    x++;
Cevabı göster

Dış döngü i = 1, 2, 4, 8, 16 değerlerini alır (iki örnekte de 32 > n). İç döngü i kez döner:

1 + 2 + 4 + 8 + 16 = 31 (n = 16 için de, n = 20 için de).

Genel olarak k = ⌊lg n⌋ ise toplam 2k+1 − 1 < 2n'dir. İç içe iki döngü olmasına rağmen parça O(n)'dir; dış döngünün lg n tur dönmesi O(n log n) sonucunu vermez, çünkü iç döngü uzunlukları geometrik dizi oluşturur.

Çoktan Seçmeli · Asimptotik Gösterim

Soru 10: Yanlış Olan İfade

Aşağıdaki ifadelerden hangisi yanlıştır?

D: n²/(n·lg n) = n/lg n sınırsız büyür; hiçbir c için n² ≤ c·n·lg n her büyük n'de sağlanmaz. A doğrudur ama bilgi vermez (sıkı sınır Θ(n)); B seçimli sıralamanın karşılaştırma sayısıdır; C'de n ≥ 2 için 10n·lg n ≥ n.

Klasik Soru · Asimptotik Gösterim

Soru 11: c ve n₀ Bulmak

f(n) = 2n² + 9n + 4 veriliyor. c = 3 seçilirse f(n) ≤ c·n² eşitsizliği hangi n₀'dan sonra hep sağlanır? f(n) = Θ(n²) olduğunu da gösteriniz.

Cevabı göster

2n² + 9n + 4 ≤ 3n² ⇔ n² − 9n − 4 ≥ 0. Kök (9 + √97)/2 ≈ 9,42 olduğundan en küçük tam sayı n₀ = 10:

n91011
f(n)247294345
3n²243300363

Alt sınır: her n ≥ 1 için f(n) ≥ 2n² → Ω(n²), c₁ = 2. İkisi birlikte: 2n² ≤ f(n) ≤ 3n² (n ≥ 10) → Θ(n²). c büyütülürse n₀ küçülür: c = 15 için n₀ = 1 yeter.

Çoktan Seçmeli · Asimptotik Gösterim

Soru 12: Üstel Büyüme

Adım sayısı 2ⁿ ile orantılı bir algoritma bir makinede n = 30 için 1 saniye sürüyor. Aynı makinede n = 40 için yaklaşık ne kadar sürer?

C: 2⁴⁰ / 2³⁰ = 2¹⁰ = 1024 kat → 1024 sn ≈ 17 dk. A doğrusal (40/30), B kübik ((40/30)³) büyüme varsayar; D, 2²⁰ sn'dir. n'ye 10 eklemek süreyi bin katına çıkarır: daha hızlı makine bu farkı kapatamaz.

Hata Bulma · Performans Ölçümü

Soru 13: Bekçinin Yeri

Sunumdaki bekçili seqsearch aşağıdaki gibi çağrılıyor. 9 arandığında kaç karşılaştırma (list[i] != searchnum) yapılır? 7 aranınca ne olur? Koddaki hata nedir?

int seqsearch(int list[], int searchnum,
              int n) {
  int i;
  list[n] = searchnum;      /* bekci */
  for (i = 0; list[i] != searchnum; i++)
    ;
  return (i < n) ? i : -1;
}
/* main: */
int a[5] = {4, 8, 2, 9, 5};
seqsearch(a, 9, 5);
seqsearch(a, 7, 5);
Cevabı göster
  • 9 için: 4 ≠ 9, 8 ≠ 9, 2 ≠ 9, 9 = 9 → 4 karşılaştırma, dönen 3.
  • 7 için: bekçi list[5] = 7 yazılır; 5 hücre + bekçi = 6 karşılaştırma (n + 1), i = 5 → −1.

Sınır hatası: a yalnızca 5 öğeliktir; list[n] = searchnum dizinin dışına, a[5]'e yazar. Bu tanımsız davranıştır: komşu bir değişken bozulabilir. Bekçili aramada dizide n + 1 yer olmalıdır: int a[6] = {4, 8, 2, 9, 5}; (sunumda MAX_SIZE = 5001).

Adım Adım Çalıştırma · Sihirli Kare

Soru 14: Sihirli Kare n = 5

sihirli(5, k) çağrısında 1–8 sayıları hangi hücrelere yazılır? Kare dolduğunda ilk satır nedir?

01234011234

İlk satırın ortası: j = (5 − 1)/2 = 2 → k[0][2] = 1.

012340112342

Sol üst çapraz (−1, 1): satır taştı → r = 4. (4, 1) boş → 2 oraya.

0123401123342

(3, 0) boş → 3.

01234011243342

Sütun taştı → c = 4. (2, 4) boş → 4.

012340115243342

(1, 3) boş → 5.

0123401152643342

Sol üst çapraz (0, 2) dolu (1 var) → bir aşağı: i = 2, j değişmez → (2, 3) = 6.

01234011752643342

(1, 2) boş → 7.

012340811752643342

(0, 1) boş → 8.

012340158124171161475232222013643321191210492251811

Döngü s = 25'te biter. İlk satır 15 8 1 24 17; her satır, sütun ve köşegen 5·26/2 = 65. 25 yerleştirme → O(n²).

void sihirli(int n, int k[][MAX]) {
  int i = 0, j = (n - 1) / 2, s, r, c;
  k[i][j] = 1;      /* k sifirlanmis */
  for (s = 2; s <= n * n; s++) {
    r = (i - 1 < 0) ? n - 1 : i - 1;
    c = (j - 1 < 0) ? n - 1 : j - 1;
    if (k[r][c]) i = (i + 1) % n;
    else { i = r; j = c; }
    k[i][j] = s;
  }
}

Çoktan Seçmeli · Performans Ölçümü

Soru 15: Sıfır Çıkan Süre

sort çağrısı yaklaşık 0,4 saniye sürüyor ve CLOCKS_PER_SEC 1000. Ölçüm parçası ne yazdırır?

clock_t start = clock();
sort(list, 2000);
clock_t stop = clock();
printf("%f\n",
  (double)((stop - start) / CLOCKS_PER_SEC));

B: clock_t bir tam sayı türüdür; (stop - start) / CLOCKS_PER_SEC önce tam sayı bölmesiyle 400 / 1000 = 0 olur, dönüşüm sonradan yapılır. Doğrusu (double)(stop - start) / CLOCKS_PER_SEC. Kısa işlerde ölçüm yine de birçok tekrarın ortalamasıyla yapılmalıdır.

Kod Yazma · Ödevler

Soru 16: Hızlı Üs Alma

xⁿ değerini (n ≥ 0) özyinelemeli hesaplayan long us(long x, int n) fonksiyonunu, n'yi her çağrıda yarıya indirerek yazınız. us(2, 10) kaç çağrı yapar? Karmaşıklık nedir?

Cevabı göster
long us(long x, int n) {
  long y;
  if (n == 0) return 1;          /* taban */
  y = us(x, n / 2);              /* tek çağrı */
  return (n % 2) ? y * y * x : y * y;
}

us(2, 10) → us(2, 5) → us(2, 2) → us(2, 1) → us(2, 0): 5 çağrı, sonuç 1024.

Her çağrıda n yarıya iner: ⌊lg n⌋ + 2 çağrı → zaman ve yığın O(log n). us(x, n/2) * us(x, n/2) yazılsaydı aynı alt problem iki kez çözülür, çağrı sayısı O(n)'e çıkardı.

Çoktan Seçmeli · Ödevler

Soru 17: komb'un Çağrı Sayısı

Sunumdaki komb fonksiyonu komb(5, 2) için toplam kaç kez çağrılır (ilk çağrı dâhil)?

long komb(int n, int m) {
  if (m == 0 || m == n) return 1;
  return komb(n - 1, m)
       + komb(n - 1, m - 1);
}

A: Her yaprak (taban durum) 1 döndürür; sonuç 10 olduğuna göre 10 yaprak vardır. İç düğümlerin her biri tam iki çağrı yaptığından iç düğüm sayısı 9'dur: 10 + 9 = 19 = 2·C(5, 2) − 1. Aynı alt problemler (ör. komb(3, 1)) tekrar tekrar çözülür.

Adım Adım Çalıştırma · Ödevler

Soru 18: fibo(4) Çağrı Ağacı

Ödev çözümündeki fibo ile fibo(4) kaç kez çağrılır ve yığın en çok kaç fibo çerçevesi derinleşir?

f(4)

n = 4 > 1: önce fibo(3) hesaplanacak (soldaki işlenenin önce çağrıldığı varsayıldı).

f(4)f(3)

fibo(3) de taban durum değil → fibo(2).

f(4)f(3)f(2)

fibo(2) → fibo(1).

f(4)f(3)f(2)f(1)=1

Taban durum: 1 döner. Yığın en derin hâlinde: 4 fibo çerçevesi.

f(4)f(3)f(2)=1f(1)=1f(0)=0

fibo(0) → 0; fibo(2) = 1 + 0 = 1 döner.

f(4)f(3)=2f(2)=1f(1)=1f(0)=0f(1)=1

fibo(3)'ün ikinci çağrısı fibo(1) = 1; fibo(3) = 1 + 1 = 2.

f(4)f(3)=2f(2)=1f(1)=1f(0)=0f(1)=1f(2)

fibo(4) sağ işlenene geçer: fibo(2) yeniden hesaplanır.

f(4)f(3)=2f(2)=1f(1)=1f(0)=0f(1)=1f(2)=1f(1)=1f(0)=0

fibo(1) = 1, fibo(0) = 0 → fibo(2) = 1.

f(4)=3f(3)=2f(2)=1f(1)=1f(0)=0f(1)=1f(2)=1f(1)=1f(0)=0

fibo(4) = 2 + 1 = 3. Toplam 9 çağrı, en çok 4 çerçeve. C, + işlenenlerinin hangi sırayla çağrılacağını belirlemez; sayı ve sonuç değişmez.

long fibo(long n) {
  if (n <= 1)
    return n;
  return fibo(n - 1) + fibo(n - 2);
}
int main(void) {
  printf("%ld\n", fibo(4));
  return 0;
}

Son

Bölüm 1: Giriş ve Algoritma Analizi — Çalışma Soruları
Konu anlatımı: Giriş ve algoritma analizi sunumu · Ders notu · Terim sözlüğü
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.