📚 Stack (Yığın) Veri Yapısı

🎯 Stack Nedir?

Stack (Yığın), Last-In-First-Out (LIFO) prensibiyle çalışan soyut bir veri yapısıdır. Yani son eklenen eleman, ilk çıkarılır.

Günlük Hayattan Örnek

Bir tabak yığınını düşünün:

  • Yeni tabakları en üste koyarsınız
  • Tabak alırken de en üsttekini alırsınız
  • En alttaki tabağa ulaşmak için üstteki tüm tabakları kaldırmanız gerekir
    ┌───────┐
    │   3   │ ← En üst (Top) - İlk çıkarılacak
    ├───────┤
    │   2   │
    ├───────┤
    │   1   │ ← En alt
    └───────┘

🔧 Temel Operasyonlar

1️⃣ push(E e) - Ekleme

Element yığının en üstüne eklenir.

push(5):  [5]
push(6):  [5, 6]
push(8):  [5, 6, 8]

2️⃣ pop() - Çıkarma ve Silme

En üstteki element döndürülür ve silinir.

pop():  8 döner → [5, 6]
pop():  6 döner → [5]

3️⃣ top() - Üsttekini Görüntüleme

En üstteki elementi döndürür, silmez.

top():  5 döner → [5] (değişmez)

4️⃣ size() - Boyut

Yığındaki toplam element sayısını döndürür.

5️⃣ isEmpty() - Boş mu?

Yığın boşsa true, değilse false döndürür.


💻 Array ile İmplementasyon

Yapı

int[] stack = new int[10];
int count = 0;  // Aktif element sayısı

İşlem Adımları

Push Operasyonu

Başlangıç:  [_, _, _, _, _, _, _, _, _, _]  count=0

push(5):    [5, _, _, _, _, _, _, _, _, _]  count=1
              ↑
            count konumu

push(6):    [5, 6, _, _, _, _, _, _, _, _]  count=2
                 ↑
               count konumu

push(8):    [5, 6, 8, _, _, _, _, _, _, _]  count=3
                    ↑
                  count konumu

Kod:

stack[count] = e;
count++;

Pop Operasyonu

Durum:      [5, 6, 8, _, _, _, _, _, _, _]  count=3

pop() → 8:  [5, 6, ∅, _, _, _, _, _, _, _]  count=2
                  ↑
                null yapıldı

pop() → 6:  [5, ∅, ∅, _, _, _, _, _, _, _]  count=1
                ↑
              null yapıldı

Kod:

E element = stack[count - 1];
stack[count - 1] = null;
count--;
return element;

🔗 Linked List ile İmplementasyon

Yapı

head → [8|•] → [6|•] → [5|null]
       ↑
     En üst

Avantajları

  • Dinamik boyut: Array gibi sabit boyut sınırı yok
  • Bellek verimliliği: Sadece gerektiği kadar alan kullanılır

Push Operasyonu

1. Durum:     head → [6|•] → [5|null]

2. Yeni node: [8|null]

3. Bağlama:   [8|•] → [6|•] → [5|null]

4. head güncelle: head → [8|•] → [6|•] → [5|null]

Pop Operasyonu

1. Durum:     head → [8|•] → [6|•] → [5|null]

2. head'i kaydet: temp = head

3. head'i kaydır: head → [6|•] → [5|null]

4. Eski head'i döndür: return 8

⏱️ Zaman Karmaşıklıkları

Operasyon Array Linked List
push(e) O(1) O(1)
pop() O(1) O(1)
top() O(1) O(1)
size() O(1) O(1)
isEmpty() O(1) O(1)

✅ Tüm operasyonlar sabit zamanlı!


📊 Karşılaştırma: Array vs Linked List

Array İmplementasyonu

✅ Avantajlar:

  • Basit ve hızlı erişim
  • Az bellek overhead’i (sadece veri)
  • Cache-friendly (bellekte ardışık)

❌ Dezavantajlar:

  • Sabit boyut sınırı
  • Taşma durumunda yeniden boyutlandırma gerekir

Linked List İmplementasyonu

✅ Avantajlar:

  • Dinamik boyut
  • Taşma sorunu yok
  • Esneklik

❌ Dezavantajlar:

  • Her node için ekstra pointer belleği
  • Cache performansı düşük
  • Biraz daha karmaşık kod

🎮 Kullanım Alanları

1. Fonksiyon Çağrı Yığını

main()
  ├─ foo()
  │   └─ bar()  ← En son çağrılan
  └─ ...

2. Geri Alma (Undo) İşlemi

İşlemler: [Sil, Yaz, Yapıştır]
Undo → Yapıştır geri alınır

3. Parantez Dengeleme

"(a + b) * (c - d)"  ✓ Dengeli
"((a + b)"           ✗ Dengesiz

4. Tarayıcı Geçmişi (Geri butonu)

Sayfa3 ← Şu an
Sayfa2
Sayfa1

💡 Özet

  • Stack LIFO prensibiyle çalışır
  • Tüm temel operasyonlar O(1) zamanda çalışır
  • Array ve Linked List ile implemente edilebilir
  • Array daha basit, Linked List daha esnektir
  • Fonksiyon çağrıları, undo işlemleri gibi birçok alanda kullanılır

🔍 Örnek Kod (Java)

public class ArrayStack<E> {
    private E[] stack;
    private int count = 0;
    
    public ArrayStack(int capacity) {
        stack = (E[]) new Object[capacity];
    }
    
    public void push(E e) {
        stack[count++] = e;
    }
    
    public E pop() {
        E element = stack[--count];
        stack[count] = null;
        return element;
    }
    
    public E top() {
        return stack[count - 1];
    }
    
    public int size() {
        return count;
    }
    
    public boolean isEmpty() {
        return count == 0;
    }
}