Bölüm 6: Yığınlar

Bölüm 6: Yığınlar · Çalışma Soruları
Yığın ADTDizi ile yığınBağlı yığınBellek ve sızıntıÇağrı yığınıÇoklu yığın
Sercan KÜLCÜ

Çoktan Seçmeli · Yığın ADT

Soru 1: Elde Edilemeyen Sıra

A, B, C, D, E harfleri bu sırayla yığına push ediliyor; aralara istenen anda pop serpiştirilebiliyor. Pop edilen harflerin sırası aşağıdakilerden hangisi olamaz?

C: D ilk çıktığında A, B, C yığındadır ve üstte C vardır. E push edilip çıkarıldıktan sonra C çıkar; bu noktada üstte B durur, A ondan önce çıkamaz. A seçeneği mümkündür: A, B, C push → C, B pop → D, E push → E, D, A pop.

Klasik Soru · Dizi ile Yığın

Soru 2: bool Döndüren push/pop

KAP 4 olan struct yığınıyla aşağıdaki kod çalıştırılıyor. Program ne yazdırır?

Yigit y; int x, i;
yigit_baslat(&y);
for (i = 1; i <= 5; i++)
  printf("%d", push(&y, i * 10));
printf("\n");
pop(&y, &x); pop(&y, &x);
push(&y, x + 1);
while (pop(&y, &x))
  printf("%d ", x);
Cevabı göster

Çıktı:

11110
31 20 10 
  • 10, 20, 30, 40 eklenir, her push 1 (true) döndürür. Beşinci push'ta ust == KAP - 1 olduğu için 50 eklenmez ve 0 (false) döner; program sürer.
  • İki pop 40'ı ve 30'u çıkarır; son değer x = 30'dur. Ardından 31 eklenir. Yığın (alttan üste): 10 20 31.
  • Döngü yığını boşaltır: 31 20 10. Dördüncü pop false döndürür ve döngü biter.

Çoktan Seçmeli · Dizi ile Yığın

Soru 3: *top++ Yazılırsa

yigit_ekle yordamında son satır yigit[*top++] = item; olarak yazılmıştır. Boş yığınla (top = -1) çağrılınca ne olur?

B: Son ek ++, tekli *'dan önce bağlanır: *(top++). İndis olarak eski *top (−1) kullanılır, ardından yalnız yerel işaretçi ilerler. Dizinin önündeki bellek bozulur (tanımsız davranış) ve çağıranın sayacı hiç değişmez. Doğrusu yigit[++*top]'tır.

Adım Adım Çalıştırma · Dizi ile Yığın

Soru 4: Yığınla İkilik Taban

ikilik_yaz(13) çağrısında yığın nasıl değişir ve ne yazdırılır?

01234ust = -1

Boş yığın kuruldu; ust = -1.

101234ust = 0

13 % 2 = 1 yığına; en düşük bit önce bulunur.

101234ust = 0

n = 13 / 2 = 6 (tam sayı bölmesi).

1001234ust = 1

6 % 2 = 0 yığına; n = 3.

10011234ust = 2

3 % 2 = 1 yığına; n = 1.

100112134ust = 3

1 % 2 = 1 yığına; n = 0 ve döngü biter.

10011234ust = 2

pop en son eklenen biti verir: en yüksek bit önce yazılır.

1001234ust = 1

Sıradaki bit 1.

101234ust = 0

Sıradaki bit 0.

01234ust = -1

Son bit 1. Sonraki pop false döner, döngü biter: 13 = 1101₂.

void ikilik_yaz(int n) {
  Yigit y; int b;
  yigit_baslat(&y);
  while (n > 0) {
    push(&y, n % 2);
    n /= 2;
  }
  while (pop(&y, &b))
    printf("%d", b);
}

Çoktan Seçmeli · Dizi ile Yığın

Soru 5: Opak Tür

yigit.h yalnızca typedef struct Yigit Yigit; bildirimini ve işlem prototiplerini içeriyor; struct Yigit'in alanları yigit.c'de tanımlı. Kullanan dosyada Yigit *y = yigit_olustur(10); y->ust = -1; yazılırsa ne olur?

B: Kullanan dosya struct Yigit'in içini görmez; derleyici ust alanının yerini bilemez ve hata verir. Opak türün amacı budur: kullanan kod yalnız yigit_ekle, yigit_al gibi işlemleri çağırır, gerçekleme değişse de etkilenmez.

Klasik Soru · Dizi ile Yığın

Soru 6: yigit_olustur'da Hatalar

Aşağıdaki yigit_olustur sürümünde üç hata var (64 bit sistem; struct Yigit { int *veri; int ust, kap; }). Hataları bulun ve düzeltin.

Yigit *yigit_olustur(int kap) {
  Yigit *y = malloc(sizeof y);
  y->veri = malloc(kap * sizeof(int));
  if (y->veri == NULL) return NULL;
  y->ust = -1; y->kap = kap;
  return y;
}
Cevabı göster
  • sizeof y işaretçinin boyutudur (8 bayt); yapı 16 bayttır. Ayrılan bloğun dışına yazılır. Doğrusu sizeof *y.
  • İlk malloc'un sonucu denetlenmiyor; NULL dönerse y->veri çöker.
  • veri ayrılamazsa y serbest bırakılmadan dönülüyor: bellek sızıntısı.
Yigit *yigit_olustur(int kap) {
  Yigit *y = malloc(sizeof *y);
  if (y == NULL) return NULL;
  y->veri = malloc(kap * sizeof *y->veri);
  if (y->veri == NULL) {
    free(y); return NULL;
  }
  y->ust = -1; y->kap = kap;
  return y;
}

Adım Adım Çalıştırma · Bağlı Yığın

Soru 7: Bağlı Yığında malloc ve free

Bağlı yığınla bu kod çalıştırılıyor. Her satırdan sonra bellek nasıl görünür; toplam kaç malloc ve free yapılır?

topNULL

Boş yığın: top = NULL. Henüz bellek ayrılmadı.

top4NULL

push: yeni düğüm ayrılır, bag eski üstü (NULL) gösterir, top yeni düğüme geçer.

top74NULL

7 başa eklenir: 7 → 4 → NULL.

top4NULL7free edildi

pop: değer okunur, top 4'e ilerler, 7'nin düğümü free ile bırakılır.

top94NULL

Yeni düğüm ayrılır: bırakılan bellek yeniden kullanılabilir ama adres garanti değildir.

top294NULL

Yığın: 2 → 9 → 4 → NULL. Üç canlı düğüm = 4 malloc − 1 free.

topNULL

yigit_temizle her düğümü bırakır: malloc = free = 4, sızıntı yok.

dugum *top = NULL; int x;
push(&top, 4);
push(&top, 7);
pop(&top, &x); printf("%d ", x);
push(&top, 9);
push(&top, 2);
yigit_temizle(&top);

Klasik Soru · Bağlı Yığın

Soru 8: Atama Sırası

Bağlı push'ta son iki atamanın yeri değiştirilmiştir. Boş yığına push(&top, 1), push(&top, 2) yapıldıktan sonra bellek nasıl görünür, ardından pop döngüsü ne yapar?

bool push(dugum **top, int x) {
  dugum *yeni = malloc(sizeof *yeni);
  if (yeni == NULL) return false;
  yeni->deger = x;
  *top = yeni;
  yeni->bag = *top;
  return true;
}
Cevabı göster

İkinci push'ta *top = yeni önce yapıldığı için yeni->bag = *top düğümü kendisine bağlar; eski liste (1'in düğümü) kaybolur.

top21hiçbir işaretçi göstermiyor
  • 1'in düğümü bellek sızıntısıdır: onu gösteren işaretçi kalmadı.
  • İlk pop 2'yi döndürür, *top = eski->bag yine aynı düğümü gösterir, sonra düğüm bırakılır: top sarkan işaretçi olur. İkinci pop serbest bırakılmış belleği okur (tanımsız davranış).
  • Doğru sıra: önce yeni->bag = *top;, sonra *top = yeni;.

Çoktan Seçmeli · Bağlı Yığın

Soru 9: Gereksiz malloc

Bağlı yığının pop yordamı aşağıdaki gibi yazılmıştır. 1000 öğeli yığın bu yordamla boşaltılırsa ne olur?

bool pop(dugum **top, int *x) {
  dugum *eski = malloc(sizeof *eski);
  if (*top == NULL) return false;
  eski = *top;
  *x = eski->deger;
  *top = eski->bag;
  free(eski);
  return true;
}

D: eski = *top; ataması ilk satırda ayrılan bloğun tek adresini ezer; o blok bir daha bırakılamaz. Sayaçlı malloc/free ile ölçüm: 1000 pop'ta 1000 ek malloc, 0 karşılık. eski yalnız bir işaretçidir; ona bellek ayırmak gerekmez.

Çoktan Seçmeli · Bağlı Yığın

Soru 10: Düğümlerin Belleği

64 bit bir sistemde int 4, işaretçi 8 bayttır. struct dugum { int deger; struct dugum *bag; } düğümleriyle 1000 tam sayı tutan bağlı yığının düğümleri kaç bayt yer kaplar (malloc'un kendi ek yükü hariç)?

C: İşaretçi 8 baytlık sınıra hizalanır; deger'den sonra 4 bayt dolgu (padding) eklenir ve sizeof(dugum) 16 olur (ölçüldü). Aynı veri dizi tabanlı yığında 4000 bayttır; bağlı yığının bedeli öğe başına işaretçi ve dolgudur.

Klasik Soru · Bağlı Yığın

Soru 11: Sırayı Koruyan Kopya

Bağlı yığının sırasını koruyarak yeni düğümlerle kopyasını döndüren dugum *yigit_kopyala(const dugum *top) yordamını yazın. Kopyada da üstteki öğe en başta olmalı; bellek yetmezse o ana kadar ayrılanlar bırakılmalı.

Cevabı göster
dugum *yigit_kopyala(const dugum *top) {
  dugum *bas = NULL, **son = &bas;
  for (; top; top = top->bag) {
    dugum *yeni = malloc(sizeof *yeni);
    if (yeni == NULL) {
      yigit_temizle(&bas); return NULL;
    }
    yeni->deger = top->deger;
    yeni->bag = NULL;
    *son = yeni;
    son = &yeni->bag;
  }
  return bas;
}

Push ile kopyalamak sırayı ters çevirirdi; bu yüzden sona ekleme yapılır. son, kopyanın son bağının adresidir (işaretçiye işaretçi): ilk düğüm için &bas. Zaman O(n), sayaçlı testte malloc = free.

Çoktan Seçmeli · Çağrı Yığını

Soru 12: Yerel Dizinin Adresi

yap()'ın döndürdüğü işaretçi için hangisi doğrudur?

int *yap(void) {
  int a[3] = {1, 2, 3};
  return a;
}

A: a, yap'ın çağrı çerçevesindedir; return ile çerçeve pop edilir ve o bellek sonraki çağrılarca kullanılabilir (sarkan işaretçi). Derleyici yalnız uyarı verir (-Wreturn-stack-address), derlemeyi durdurmaz. Çözüm: malloc ile heap'ten ayırmak ya da diziyi çağırandan almak.

Klasik Soru · Çağrı Yığını

Soru 13: Çağrı Sayısı ve Derinlik

f(5) çağrıldığında toplam kaç f çağrısı yapılır? Çağrı yığınında aynı anda en çok kaç çerçeve bulunur (main dahil)?

void f(int n) {
  if (n <= 1) return;
  f(n - 1);
  f(n - 2);
}
Cevabı göster

Çağrı sayısı C(n) = 1 + C(n−1) + C(n−2), C(1) = C(0) = 1: C(2) = 3, C(3) = 5, C(4) = 9, C(5) = 15.

Yığında aynı anda yalnız bir yolun çerçeveleri bulunur: f(5) → f(4) → f(3) → f(2) → f(1). Bu 5 çerçeve ve main ile en çok 6.

Zaman toplam çağrı sayısıyla, yığın belleği en derin yolla orantılıdır. Sayaçlı programla doğrulandı.

Adım Adım Çalıştırma · Çoklu Yığın

Soru 14: Tek Dizide İki Yığın

Boş durumdan başlayarak sırayla ekle(1,5), ekle(2,9), ekle(2,4), ekle(1,7), ekle(2,3), ekle(1,8), ekle(2,6) ve al(2) yapılıyor. Hangi çağrı başarısız olur?

012345

M = 6. Yığın 1 soldan sağa, yığın 2 sağdan sola büyür. Boş: top1 = −1, top2 = M.

5012345top1

ekle(1, 5): top1 + 1 ≠ top2; bellek[++top1] = 5.

50123495top1top2

ekle(2, 9): bellek[--top2] = 9; top2 = 5.

501234495top1top2

ekle(2, 4): top2 = 4.

5071234495top1top2

ekle(1, 7): top1 = 1.

50712334495top1top2

ekle(2, 3): top2 = 3.

507182334495top1top2

ekle(1, 8): top1 = 2. Artık top1 + 1 == top2: dizi tümüyle dolu.

507182334495top1top2

ekle(2, 6) false döner. Dolu koşulu iki yığın için ortaktır: hiç hücre boşa gitmedi.

50718234495top1top2

al(2): bellek[top2++] = 3 döner. Boşalan hücreyi artık iki yığın da kullanabilir.

bool ekle(int k, int x) {
  if (top1 + 1 == top2) return false;
  if (k == 1) bellek[++top1] = x;
  else        bellek[--top2] = x;
  return true;
}

Çoktan Seçmeli · Çoklu Yığın

Soru 15: Kesim Sınırları

m = 20 hücrelik bellek n = 4 yığına eşit bölünüyor; başta top[i] = sinir[i] = (m/n)·i − 1 ve sinir[n] = m − 1. Yığın 2 hangi hücreleri kullanır, boş ve dolu koşulu nedir?

A: sinir = [−1, 4, 9, 14, 19]. Yığın i, bellek[sinir[i]+1 .. sinir[i+1]] aralığını kullanır: 10..14. Boş: top[2] == sinir[2] = 9; dolu: top[2] == sinir[3] = 14. C seçeneği top'u ilk öğenin indisi sanır; oysa boş yığında top kesimin bir öncesini gösterir.

Çoktan Seçmeli · Özet

Soru 16: Üç Öğede Çıkış Sıraları

1, 2, 3 bu sırayla push ediliyor; aralara istenen anda pop konabiliyor. Kaç farklı çıkış sırası elde edilebilir ve hangisi elde edilemez?

D: 3 ilk çıkarsa 1 ve 2 yığındadır, üstte 2 vardır; 1 ondan önce çıkamaz. 2 3 1 mümkündür: push 1, push 2, pop, push 3, pop, pop. Olası sıra sayısı Catalan sayısıdır: C₃ = 5.

Son

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