📚 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;
}
}