Bölüm 7: Yığınlar
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. | 1 | 2 | 3 | 4 | 5 | 6–8 | 9 |
|---|---|---|---|---|---|---|---|
| büyütme | — | 1→2 | 2→4 | — | 4→8 | — | 8→16 |
| kopya | 0 | 1 | 2 | 0 | 4 | 0 | 8 |
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 | İşlem | Yığı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
| i | dizi[i] | pop edilenler | sonuc[i] | yığın (alt→üst) |
|---|---|---|---|---|
| 6 | 1 | — | −1 | 1 |
| 5 | 7 | 1 | −1 | 7 |
| 4 | 5 | — | 7 | 7 5 |
| 3 | 5 | 5 (≤ 5) | 7 | 7 5 |
| 2 | 9 | 5, 7 | −1 | 9 |
| 1 | 2 | — | 9 | 9 2 |
| 0 | 6 | 2 | 9 | 9 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 | İşlem | Yığın (alt→üst) |
|---|---|---|
| 6, 2, 3 | 3 × push | 6 2 3 |
| + | sag = 3, sol = 2 → 2 + 3 = 5 | 6 5 |
| * | sag = 5, sol = 6 → 6 · 5 = 30 | 30 |
| 8, 4 | 2 × push | 30 8 4 |
| / | sag = 4, sol = 8 → 8 / 4 = 2 | 30 2 |
| − | sag = 2, sol = 30 → 30 − 2 = 28 | 28 |
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 | çıkan | yığı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
| İşlem | geri (alt→üst) | şu anki | ileri (alt→üst) |
|---|---|---|---|
| ziyaret(Mail) | Ana | boş | |
| ziyaret(Harita) | Ana Mail | Harita | boş |
| ziyaret(Video) | Ana Mail Harita | Video | boş |
| geri() | Ana Mail | Harita | Video |
| geri() | Ana | Video Harita | |
| ileri() | Ana Mail | Harita | Video |
| ziyaret(Blog) | Ana Mail Harita | Blog | boş |
| geri() | Ana Mail | Harita | Blog |
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).