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

Bölüm 7: Yığınlar · Çalışma Soruları
Yığın ADT ve LIFODizi ve bağlı liste ile gerçeklemeAmortize analizYığın uygulamalarıHanoi ve stock spanInfix, postfix, prefix
Sercan KÜLCÜ · Giresun Üniversitesi · Bilgisayar Mühendisliği

Klasik Soru · Yığın ADT

Soru 1: push/pop Çıktısı

Aşağıdaki kod parçasının çıktısı nedir?

Deque<Integer> y = new ArrayDeque<>();
y.push(4); y.push(9); y.push(2);
System.out.print(y.pop() + " ");
y.push(7);
System.out.print(y.peek() + " ");
System.out.print(y.pop() + y.pop() + " ");
y.push(5);
System.out.print(y.size() + " " + y.peek());
Cevabı göster

Çıktı: 2 7 16 2 5

  • 4, 9, 2 eklenir; üstte 2 → pop() 2 döndürür (LIFO). Yığın (alt→üst): 4 9.
  • 7 eklenir; peek() 7'yi çıkarmadan döndürür.
  • y.pop() + y.pop() önce tam sayı toplamıdır: 7 + 9 = 16. Yığın: 4.
  • 5 eklenir: yığın 4 5 → size() 2, peek() 5.

Klasik Soru · Yığın ADT

Soru 2: İşlem Dizisi ve Son Yığın

Boş bir yığına sırayla aşağıdaki işlemler uygulanıyor. Her pop() hangi değeri döndürür? Sonda yığında hangi öğeler kalır ve en üstte hangisi vardır?

push(5), push(3), pop(), push(8),
push(1), pop(), pop(), push(4)
Cevabı göster
  • push(5), push(3) → [5, 3]; pop() → 3
  • push(8), push(1) → [5, 8, 1]; pop() → 1; pop() → 8
  • push(4) → [5, 4]

pop değerleri: 3, 1, 8. Yığında alttan üste 5, 4 kalır; en üstte 4 vardır.

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

Soru 3: Olası Çıkış Sıraları

1, 2, 3, 4 sayıları bu sırayla yığına push ediliyor; aralara istenen anda pop() serpiştirilebiliyor. Pop edilen değerlerin sırası aşağıdakilerden hangisi olamaz?

C: 4 ilk çıkıyorsa 1, 2, 3 hâlâ yığındadır ve üstte 3 vardır; sıradaki pop 3 olmak zorundadır, 2 olamaz. A ise mümkündür: push 1, 2, 3 → pop 3, pop 2 → push 4, pop 4 → pop 1.

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

Soru 4: Dizi Yığında top ve size

Kapasitesi kap olan dizi tabanlı yığında top üstteki öğenin indisidir ve boş yığında top = −1'dir. "Dolu" koşulu ve size() hangisidir?

B: Son geçerli indis kap − 1'dir; indisler 0'dan başladığı için öğe sayısı top + 1'dir. A en sık yapılan top/size karışıklığıdır: top == kap olduğunda veri[top] zaten dizinin dışındadır.

Klasik Soru · Gerçekleme

Soru 5: Çıkarılan Hücre

Nesne tutan dizi tabanlı yığının bu pop() metodu doğru değeri döndürür ama bir kusuru vardır. Kusur nedir ve nasıl düzeltilir?

public E pop() {
  if (isEmpty())
    throw new RuntimeException("boş");
  return veri[top--];
}
Cevabı göster

Çıkarılan öğenin referansı veri[top+1] hücresinde kalır. Yığın o nesneyi artık kullanmasa da dizi onu gösterdiği için çöp toplayıcı nesneyi temizleyemez (bellek sızıntısı, loitering).

public E pop() {
  if (isEmpty())
    throw new RuntimeException("boş");
  E x = veri[top];
  veri[top--] = null; // bırak
  return x;
}

İşlem yine O(1)'dir. İlkel tür (int[]) tutan yığında bu sorun yoktur.

Adım Adım Çalıştırma · Gerçekleme

Soru 6: Sınırlı Dizi Yığını İzleme

Derste yazılan DiziYigin sınıfıyla bu kod çalıştırılıyor. Her satırdan sonra veri dizisi ve top ne olur, program ne yazdırır?

3 hücrelik dizi, hepsi null; boş yığında top = −1.

top (−1) ≠ 2 → yer var. veri[++top] = 10: önce top 0 olur, sonra yazılır.

top 1 olur, veri[1] = 20.

x = veri[1] = 20 saklanır, hücre null yapılır, top 0'a iner; 20 yazdırılır (LIFO).

Boşalan 1. hücre yeniden kullanılır: veri[1] = 30.

top 2 olur, veri[2] = 40. Dizi artık dolu.

top() 40'ı çıkarmadan döndürür; size() = top + 1 = 3.

top == veri.length − 1 (2 == 2) → taşma istisnası. Dinamik dizi burada büyürdü.

DiziYigin<Integer> y = new DiziYigin<>(3);
y.push(10);
y.push(20);
System.out.println(y.pop());
y.push(30);
y.push(40);
System.out.println(y.top() + " " + y.size());
y.push(50);

Klasik Soru · Gerçekleme

Soru 7: İki Katına Büyütme Maliyeti

Kapasitesi 1 olan ve dolunca kapasitesini iki katına çıkaran (eski öğeleri yeni diziye kopyalayan) boş bir yığına 9 kez push yapılıyor. Toplam kaç kopyalama ve kaç yazma yapılır, son kapasite kaçtır ve bu sonuç push'un amortize maliyeti hakkında ne söyler?

Cevabı göster
push no.123456–89
büyütme—1→22→4—4→8—8→16
kopya0120408

Kopya: 1 + 2 + 4 + 8 = 15, yazma: 9, toplam 24; son kapasite 16.

24 < 3n = 27: n push'ta kopyalar 1 + 2 + 4 + … < 2n olduğundan toplam < 3n'dir; push başına ortalama < 3 → amortize O(1). Yine de büyütme yapan tek bir push (9. push) O(n) sürer; amortize sınır uzun bir işlem dizisinin ortalamasıdır.

Çoktan Seçmeli · Gerçekleme

Soru 8: Sabit Miktarda Büyütme

Dinamik dizi yığını, dolduğunda kapasitesini iki katına çıkarmak yerine 10 hücre artırıyor (10 → 20 → 30 → …). Boş yığına n push yapıldığında toplam maliyet ve push başına ortalama maliyet nedir?

C: Kopyalar 10 + 20 + 30 + … + n ≈ n²/20 → O(n²); n push'a bölünce push başına O(n). A yalnızca kapasite oranla (ör. ×2) büyütülünce doğrudur: o zaman kopyalar geometrik dizi oluşturur ve toplam < 3n kalır.

Çoktan Seçmeli · Gerçekleme

Soru 9: Dizi mi, Bağlı Liste mi?

Yığın gerçeklemeleri hakkındaki ifadelerden hangisi yanlıştır?

A yanlıştır: büyütme yapan push tüm öğeleri kopyalar, O(n) sürer; O(1) olan amortize maliyettir. D doğrudur: Stack Vector tabanlıdır ve senkronize olduğu için daha yavaştır. Bağlı listede öğe başına sonraki referansı ek bellek tutar.

Klasik Soru · Yığın Uygulamaları

Soru 10: Parantez Kontrolü İzleme

Dersteki gecerliMi metodu "[{()()}]{" girdisi için hangi değeri döndürür? Her karakterden sonra yığının durumunu yazarak gösterin.

Cevabı göster
KarakterİşlemYığın (alt→üst)
[ { (3 × push[ { (
)pop ( ✓[ {
(push[ { (
)pop ( ✓[ {
}pop { ✓[
]pop [ ✓boş
{push{
(son)yığın boş mu?{ kaldı

Sonuç: false. Tüm kapanışlar doğru eşleşti ama sonda yığında kapanmamış { kaldı; return yigin.isEmpty() false verir. Zaman O(n), yığın en çok O(n).

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

Soru 11: Boş Yığın Kontrolü

gecerliMi metodundan işaretli satır silinirse aşağıdaki girdilerden hangisi istisna fırlatır?

for (char c : s.toCharArray()) {
  if (c == '(' || c == '[' || c == '{') {
    yigin.push(c);
  } else {
    if (yigin.isEmpty()) return false; // silindi
    char acik = yigin.pop();
    if (!eslesir(acik, c)) return false;
  }
}
return yigin.isEmpty();

D: "()" eşleşip yığın boşaldıktan sonra gelen ikinci ) boş ArrayDeque'ten pop yapar → NoSuchElementException. A istisna vermez: sonda yığında ( kalır ve false döner. B'de ) gelince üstte [ vardır, eşleşmez → false; C geçerlidir → true.

Klasik Soru · Yığın Uygulamaları

Soru 12: Sonraki Büyük Öğe

sonrakiBuyuk(new int[]{6, 2, 9, 5, 5, 7, 1}) ne döndürür? Dizi sağdan sola gezilirken yığının değişimini gösterin.

for (int i = dizi.length-1; i >= 0; i--) {
  while (!yigin.isEmpty() &&
         yigin.peek() <= dizi[i])
    yigin.pop();
  sonuc[i] = yigin.isEmpty()
           ? -1 : yigin.peek();
  yigin.push(dizi[i]);
}
Cevabı göster
idizi[i]pop edilenlersonuc[i]yığın (alt→üst)
61—−11
571−17
45—77 5
355 (≤ 5)77 5
295, 7−19
12—99 2
06299 6

Sonuç: [9, 9, −1, 7, 7, −1, −1]. Yığın alttan üste azalan kalır (monoton yığın). Her öğe en fazla bir kez push ve bir kez pop edilir → O(n) (kaba kuvvet O(n²)).

Klasik Soru · Yığın Uygulamaları

Soru 13: getMin O(1) Olan Yığın

Sırayla push(4), push(6), push(2), push(2), pop(), getMin(), pop(), getMin() yapılıyor. İki getMin() çağrısı ne döndürür ve en sonda min yığınında ne kalır?

void push(int x) {
  y.push(x);
  if (min.isEmpty() || x <= min.peek())
    min.push(x);
}
int pop() {
  int x = y.pop();
  if (x == min.peek()) min.pop();
  return x;
}
int getMin() { return min.peek(); }
Cevabı göster
  • push'lardan sonra y (alt→üst): 4 6 2 2; min: 4 2 2 (6 > 4 olduğu için eklenmez; ikinci 2, <= sayesinde eklenir).
  • pop() → 2; 2 == min.peek() → min: 4 2. getMin() → 2.
  • pop() → 2; min: 4. getMin() → 4.

Sonda min yığını: 4. getMin yalnızca peek yapar → O(1).

< yazılsaydı ikinci 2 min'e eklenmez, ilk pop'ta min'deki tek 2 de atılır ve ilk getMin() yanlışlıkla 4 döndürürdü (yığında hâlâ bir 2 vardır).

Adım Adım Çalıştırma · Hanoi ve Stock Span

Soru 14: Stock Span İzleme

span({30, 20, 25, 10, 15, 40}) hangi diziyi döndürür?

İlk gün: indis 0 yığına, span 1. Yığında henüz aşılmamış günlerin indisleri tutulur.

20 ≥ fiyatlar[0] = 30? Hayır → span = 1 − 0 = 1; push(1).

25 ≥ fiyatlar[1] = 20 → pop(1). 1. gün artık kimsenin sınırı olamaz.

25 < 30 → durur. span = 2 − 0 = 2; push(2).

10 < 25 → span = 3 − 2 = 1; push(3).

15 ≥ fiyatlar[3] = 10 → pop(3).

15 < 25 → span = 4 − 2 = 2; push(4).

40 ≥ 15 → pop(4); 40 ≥ 25 → pop(2).

40 ≥ 30 → pop(0). Yığın boşaldı: 40 tüm önceki fiyatları aştı.

Yığın boş → span = i + 1 = 6; push(5).

Her indis bir kez push, en çok bir kez pop edilir → O(n).

int[] span(int[] fiyatlar) {
  int[] sicrama = new int[fiyatlar.length];
  Deque<Integer> yigin = new ArrayDeque<>();
  yigin.push(0); sicrama[0] = 1;
  for (int i = 1; i < fiyatlar.length; i++) {
    while (!yigin.isEmpty() &&
        fiyatlar[i] >= fiyatlar[yigin.peek()])
      yigin.pop();
    sicrama[i] = yigin.isEmpty() ? i + 1
               : i - yigin.peek();
    yigin.push(i);
  }
  return sicrama;
}

Çoktan Seçmeli · İfade Gösterimleri

Soru 15: Sağdan Birleşen Üs

^ (üs) en yüksek önceliklidir ve sağdan sola birleşir. A ^ B ^ C * D ifadesinin postfix karşılığı hangisidir?

C: Sağdan birleşme (A ^ (B ^ C)) * D demektir. A seçeneği (A ^ B) ^ C'yi, yani soldan birleşmeyi yansıtır. Algoritmada bu yüzden ^ geldiğinde üstteki eşit öncelikli ^ çıkarılmaz; yalnızca önceliği daha büyük olanlar çıkarılır.

Adım Adım Çalıştırma · İfade Gösterimleri

Soru 16: Infix → Postfix İzleme

infixToPostfix("A-B*(C+D)/E") hangi diziyi döndürür?

Öncelik: + − → 1, * / → 2, ( → 0.

İşlenen → doğrudan çıktıya.

Yığın boş → push(−).

İşlenen → çıktıya.

Üstteki − (1) ≥ * (2)? Hayır → push(*).

( her zaman yığına.

İşlenen → çıktıya.

Üstte ( (öncelik 0) → hiçbir şey çıkmaz, push(+).

İşlenen → çıktıya.

) → ( görülene kadar pop: + çıktıya.

( atılır; parantezler çıktıya yazılmaz.

Üstteki * (2) ≥ / (2) → * çıktıya (soldan birleşme).

Üstteki − (1) ≥ 2? Hayır → push(/).

İşlenen → çıktıya.

Girdi bitti: önce /, sonra − çıktıya. Sonuç: A B C D + * E / −. O(n).

for (char c : ifade.toCharArray()) {
  if (Character.isLetterOrDigit(c))
    cikti.append(c);
  else if (c == '(') yigin.push(c);
  else if (c == ')') {
    while (yigin.peek() != '(')
      cikti.append(yigin.pop());
    yigin.pop();  // '(' atılır
  } else {        // işleç
    while (!yigin.isEmpty() &&
        oncelik(yigin.peek()) >= oncelik(c))
      cikti.append(yigin.pop());
    yigin.push(c);
  }
}
while (!yigin.isEmpty())
  cikti.append(yigin.pop());

Klasik Soru · İfade Gösterimleri

Soru 17: Postfix Değerlendirme

postfixDegerlendir("623+*84/-") çağrısının sonucunu bulun; her simgeden sonra işlenen yığınının durumunu yazın.

Cevabı göster
OkunanİşlemYığın (alt→üst)
6, 2, 33 × push6 2 3
+sag = 3, sol = 2 → 2 + 3 = 56 5
*sag = 5, sol = 6 → 6 · 5 = 3030
8, 42 × push30 8 4
/sag = 4, sol = 8 → 8 / 4 = 230 2
−sag = 2, sol = 30 → 30 − 2 = 2828

Sonuç: 28 (infix karşılığı 6 * (2 + 3) − 8 / 4). Sonda yığında tek değer kalır. Parantez ve öncelik gerekmez; her simge bir kez işlenir → O(n).

Çoktan Seçmeli · İfade Gösterimleri

Soru 18: İşlenen Sırası

Dersteki postfixDegerlendir("82/3-") çağrısı hangi değeri döndürür?

if (Character.isDigit(c)) {
  yigin.push(c - '0');
} else {
  int sag = yigin.pop();
  int sol = yigin.pop();
  yigin.push(hesapla(sol, c, sag));
}

D: / için önce sag = 2, sonra sol = 8 çıkar → 8 / 2 = 4; − için sag = 3, sol = 4 → 4 − 3 = 1. A (3), işlenen sırası karıştırılınca çıkar: 2 / 8 = 0 (tam sayı bölmesi), sonra 3 − 0 = 3. İlk pop sağ, ikinci pop sol işlenendir.

Çoktan Seçmeli · Özet

Soru 19: Yazdırma Sırası

Aşağıdaki kodun çıktısı nedir?

Stack<Integer> s = new Stack<>();
Deque<Integer> d = new ArrayDeque<>();
for (int i = 1; i <= 3; i++) {
  s.push(i);
  d.push(i);
}
System.out.println(s + " " + d);

A: Eski Stack (Vector tabanlı) alttan üste, ArrayDeque ise üstten alta (push başa ekler) yazdırır ve gezinir. İki yığın aynı içeriğe sahip olsa da çıktılar ters görünür; for-each ile gezinirken de aynı fark vardır.

Çoktan Seçmeli · İfade Gösterimleri

Soru 20: Infix → Prefix

Dersteki infixToPrefix (ters çevir, ( ↔ ), eşit öncelikte pop etmeyen postfix, sonucu ters çevir) "A-B+C*D/E" için ne döndürür?

B: Soldan birleşme (A − B) + ((C * D) / E) demektir. A, 3. adımda eşit öncelikte de pop edilince çıkar; ters çevirince birleşme sağdan olur: A − (B + C * (D / E)). C ifadenin postfix karşılığıdır. D, 3. adımın çıktısıdır; son ters çevirme unutulmuştur.

Klasik Soru · Hanoi ve Stock Span

Soru 21: Hanoi Görev Yığını

Dersteki yığınlı hanoi metodu hanoi(4) ile çağrılıyor; Gorev(n, k, y, h): n diski k'dan h'ye, y yardımıyla taşı. İlk üç pop'tan sonra yığında (üstten alta) hangi görevler vardır? İlk yazdırılan hamle nedir ve yığın en çok kaç görev tutar?

yigin.push(new Gorev(n, 'A', 'B', 'C'));
while (!yigin.isEmpty()) {
  Gorev g = yigin.pop();
  if (g.n() == 1)
    System.out.println(g.k() + " → " + g.h());
  else {             // ters sırayla
    int m = g.n() - 1;
    yigin.push(new Gorev(m, g.y(), g.k(), g.h()));
    yigin.push(new Gorev(1, g.k(), g.y(), g.h()));
    yigin.push(new Gorev(m, g.k(), g.h(), g.y()));
  }
}
Cevabı göster
popçıkanyığın (üstten alta)
1(4,A,B,C)(3,A,C,B) (1,A,B,C) (3,B,A,C)
2(3,A,C,B)(2,A,B,C) (1,A,C,B) (2,C,A,B) (1,A,B,C) (3,B,A,C)
3(2,A,B,C)(1,A,C,B) (1,A,B,C) (1,B,A,C) (1,A,C,B) (2,C,A,B) (1,A,B,C) (3,B,A,C)

4. pop (1,A,C,B) → ilk hamle A → B (disk 1). n çift olduğu için en küçük disk önce B'ye gider; hanoi(3)'te ilk hamle A → C idi.

Her genişletme 1 görev çıkarıp 3 ekler (net +2) ve üst üste n − 1 kez olur: yığın en çok 7 = 2n − 1 görev tutar. Toplam 2⁴ − 1 = 15 hamle yazdırılır.

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

Soru 22: Çağrı Yığınının Derinliği

Çağrı yığını en derin olduğu anda yığında (main dahil) kaç çerçeve vardır ve en üstteki çerçeve hangisidir?

int fakt(int n) {
  if (n <= 1)
    return 1;
  return n * fakt(n - 1);
}
// main içinde:
System.out.println(fakt(4));

D: main → fakt(4) → fakt(3) → fakt(2) → fakt(1). Taban durum n <= 1 olduğu için fakt(0) hiç çağrılmaz (B). C, main'in çerçevesini saymaz. A yığını ters okur: fakt(4) main'in hemen üstünde bekler; en üstte en son çağrılan durur. Derinlik n + 1 → O(n) bellek.

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

Soru 23: StackOverflowError

Taban durum n == 1 olarak yazılmış. fakt(0) çağrıldığında ne olur?

int fakt(int n) {
  if (n == 1)
    return 1;
  return n * fakt(n - 1);
}
// main içinde:
System.out.println(fakt(0));

A: n = 0, −1, −2, … taban duruma hiç ulaşmaz; her çağrı yığına yeni bir çerçeve iter ve iş parçacığının sınırlı yığın alanı dolunca JVM StackOverflowError fırlatır. D sonsuz döngü için doğru olurdu; özyinelemede her çağrı bellek tükettiği için program çöker. B ve C taban durumun 0'ı yakaladığını varsayar; n <= 1 yazılsaydı 1 dönerdi.

Klasik Soru · Yığın Uygulamaları

Soru 24: Geri / İleri İzleme

Tarayıcı dersteki iki yığın kuralıyla çalışıyor: ziyaret → şu anki sayfa geri'ye push, ileri temizlenir; geri → şu anki ileri'ye push, geri'den pop; ileri → şu anki geri'ye push, ileri'den pop.

Şu anki sayfa Ana, iki yığın boş. Sırayla ziyaret(Mail), ziyaret(Harita), ziyaret(Video), geri(), geri(), ileri(), ziyaret(Blog), geri() yapılıyor. Her işlemden sonra iki yığını ve şu anki sayfayı yazın. Sonda Video'ya ileri() ile dönülebilir mi?

Cevabı göster
İşlemgeri (alt→üst)şu ankiileri (alt→üst)
ziyaret(Mail)AnaMailboş
ziyaret(Harita)Ana MailHaritaboş
ziyaret(Video)Ana Mail HaritaVideoboş
geri()Ana MailHaritaVideo
geri()AnaMailVideo Harita
ileri()Ana MailHaritaVideo
ziyaret(Blog)Ana Mail HaritaBlogboş
geri()Ana MailHaritaBlog

Son durumda ileri() Blog'u açar. Video'ya ileri ile dönülemez: ziyaret(Blog) yeni bir yol açtığı için ileri yığınını (içinde Video vardı) temizledi. Her işlem O(1).

Son

Bölüm 7: Yığınlar: Çalışma Soruları
Konu anlatımı: Yığın sunumu
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.