Bölüm 6: Yığınlar
Ç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 - 1olduğ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?
Boş yığın kuruldu; ust = -1.
13 % 2 = 1 yığına; en düşük bit önce bulunur.
n = 13 / 2 = 6 (tam sayı bölmesi).
6 % 2 = 0 yığına; n = 3.
3 % 2 = 1 yığına; n = 1.
1 % 2 = 1 yığına; n = 0 ve döngü biter.
pop en son eklenen biti verir: en yüksek bit önce yazılır.
Sıradaki bit 1.
Sıradaki bit 0.
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 yişaretçinin boyutudur (8 bayt); yapı 16 bayttır. Ayrılan bloğun dışına yazılır. Doğrususizeof *y.- İlk
malloc'un sonucu denetlenmiyor; NULL dönersey->veriçöker. veriayrılamazsayserbest 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?
Boş yığın: top = NULL. Henüz bellek ayrılmadı.
push: yeni düğüm ayrılır, bag eski üstü (NULL) gösterir, top yeni düğüme geçer.
7 başa eklenir: 7 → 4 → NULL.
pop: değer okunur, top 4'e ilerler, 7'nin düğümü free ile bırakılır.
Yeni düğüm ayrılır: bırakılan bellek yeniden kullanılabilir ama adres garanti değildir.
Yığın: 2 → 9 → 4 → NULL. Üç canlı düğüm = 4 malloc − 1 free.
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.
- 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->bagyine aynı düğümü gösterir, sonra düğüm bırakılır:topsarkan 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 = ¥i->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?
M = 6. Yığın 1 soldan sağa, yığın 2 sağdan sola büyür. Boş: top1 = −1, top2 = M.
ekle(1, 5): top1 + 1 ≠ top2; bellek[++top1] = 5.
ekle(2, 9): bellek[--top2] = 9; top2 = 5.
ekle(2, 4): top2 = 4.
ekle(1, 7): top1 = 1.
ekle(2, 3): top2 = 3.
ekle(1, 8): top1 = 2. Artık top1 + 1 == top2: dizi tümüyle dolu.
ekle(2, 6) false döner. Dolu koşulu iki yığın için ortaktır: hiç hücre boşa gitmedi.
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.