
Yazılım dünyasına adım atan veya bu alanda kendini geliştirmek isteyen herkesin er ya da geç karşılaşacağı temel konulardan biri de veri yapılarıdır. Veri yapıları, elimizdeki bilgiyi bilgisayarın belleğinde nasıl düzenleyeceğimizi ve bu bilgiye nasıl erişeceğimizi belirler. Tıpkı bir evin odalarını düzenlemek gibi, veri yapıları da kodunuzun daha düzenli, verimli ve anlaşılır olmasını sağlar. Yazılımcılık kariyerimin başından beri gördüm ki, bu temel kavramları sağlam oturtmak, ileride karşılaşılacak daha karmaşık sorunları çözmek için paha biçilmez bir temel oluşturuyor.
Bu yazımda size, yazılımın iki temel ve en sık kullanılan veri yapısından bahsedeceğim: Yığın (Stack) ve Kuyruk (Queue). Bu iki yapı arasındaki farkları, nasıl çalıştıklarını ve gerçek dünyada hangi senaryolarda karşımıza çıktıklarını kendi tecrübelerimden süzerek anlatmaya çalışacağım. Eğer yazılım öğrenme yolculuğundaysanız veya sadece bu temel yapıları daha iyi anlamak istiyorsanız, doğru yerdesiniz. Gelin, 2025 yılına doğru ilerlerken bu temel bilgileri tazeleyelim ve neden hala bu kadar önemli olduklarını görelim.

Temel Kavramlar: Yığın (Stack) Nedir?
Yığın (Stack), doğrusal bir veri yapısıdır ve elemanların belirli bir sırayla eklendiği ve çıkarıldığı bir prensibe dayanır. Bu prensip Son Giren İlk Çıkar (LIFO – Last-In, First-Out) veya diğer adıyla İlk Giren Son Çıkar (FILO – First-In, Last-Out) olarak bilinir. En güzel benzetmesi, üst üste dizilmiş tabaklardır. Yeni bir tabak eklemek istediğinizde en üste koyarsınız. Tabak almak istediğinizde de en üsttekini alırsınız. Yani en son koyduğunuz tabağı ilk olarak alırsınız.
Yığın veri yapısında iki temel işlem bulunur:
- Push: Yığına yeni bir eleman ekleme işlemidir. Eleman her zaman yığının en üstüne eklenir.
- Pop: Yığından eleman çıkarma işlemidir. Her zaman yığının en üstündeki eleman çıkarılır.
Bunların dışında, yığının en üstündeki elemana erişmek için (onu çıkarmadan) Top veya Peek gibi işlemler de bulunur. Yığın boşken Pop yapmaya çalışmak Underflow, yığın doluyken Push yapmaya çalışmak ise Overflow hatasına neden olabilir (eğer yığının boyutu sabitse).
Çoğu modern programlama dilinde veya kütüphanesinde (C++ STL gibi), yığın yapısı hazır olarak gelir. Kullanımı oldukça basittir:
#include <stack>
// Integer tipinde bir yığın tanımla
std::stack<int> benimYiginim;
// Yığına eleman ekle (Push)
benimYiginim.push(10);
benimYiginim.push(20); // 20, 10'un üstüne gelir
// Yığının en üstündeki elemana bak (Top)
int enUstteki = benimYiginim.top(); // enUstteki = 20
// Yığının en üstündeki elemanı çıkar (Pop)
benimYiginim.pop(); // 20 çıkarıldı, şimdi en üstte 10 var
// Yığın boş mu kontrol et (Empty)
if (benimYiginim.empty()) {
// Yığın boşsa burası çalışır
}
// Yığındaki eleman sayısını al (Size)
size_t yiginBoyutu = benimYiginim.size(); // yiginBoyutu = 1 (çünkü 10 kaldı)
Gördüğünüz gibi, yığının çalışma mantığı ve temel işlemleri oldukça anlaşılır. Bu basitlik, onu belirli senaryolarda inanılmaz derecede güçlü kılar.

Peki Ya Kuyruk (Queue)? FIFO Mantığı Nasıl İşler?
Kuyruk (Queue) da tıpkı yığın gibi doğrusal bir veri yapısıdır, ancak farklı bir prensiple çalışır. Kuyruk, İlk Giren İlk Çıkar (FIFO – First-In, First-Out) prensibine dayanır. Bu, hepimizin günlük hayattan bildiği bir kuyruk gibidir. Bir sıraya girdiğinizde (bir market kuyruğu, banka kuyruğu), en öndeki ilk hizmeti alır ve sıradan ayrılır. Yeni gelenler ise sıranın en arkasına eklenir.
Kuyruk veri yapısında da iki temel işlem bulunur:
- Enqueue (Push): Kuyruğa yeni bir eleman ekleme işlemidir. Eleman her zaman kuyruğun sonuna (arkasına) eklenir.
- Dequeue (Pop): Kuyruktan eleman çıkarma işlemidir. Her zaman kuyruğun başındaki (önündeki) eleman çıkarılır.
Kuyruğun başındaki elemana erişmek için Front, sonundaki elemana erişmek için ise Back veya Rear işlemleri kullanılabilir. Yığın gibi, kuyruk da çoğu programlama dilinde veya kütüphanesinde mevcuttur:
#include <queue>
// String tipinde bir kuyruk tanımla
std::queue<std::string> benimKuyrugum;
// Kuyruğa eleman ekle (Enqueue/Push)
benimKuyrugum.push("İlk islem");
benimKuyrugum.push("İkinci islem"); // "İkinci islem", "İlk islem"in arkasına geçer
// Kuyruğun başındaki elemana bak (Front)
std::string enOndeki = benimKuyrugum.front(); // enOndeki = "İlk islem"
// Kuyruğun sonundaki elemana bak (Back)
std::string enArkdaki = benimKuyrugum.back(); // enArkdaki = "İkinci islem"
// Kuyruğun başındaki elemanı çıkar (Dequeue/Pop)
benimKuyrugum.pop(); // "İlk islem" çıkarıldı, şimdi en önde "İkinci islem" var
// Kuyruk boş mu kontrol et (Empty)
if (benimKuyrugum.empty()) {
// Kuyruk boşsa burası çalışır
}
// Kuyruktaki eleman sayısını al (Size)
size_t kuyrukBoyutu = benimKuyrugum.size(); // kuyrukBoyutu = 1 (çünkü "İkinci islem" kaldı)
Gördüğünüz gibi, kuyruk da oldukça basit bir yapıya sahip. Temel fark, elemanların giriş ve çıkış sırasındaki prensiptir: Yığında “son giren” öncelikliyken, Kuyrukta “ilk giren” önceliklidir.
Gerçek Dünya Uygulamaları: Stack ve Queue Nerelerde Karşımıza Çıkar?
Bu iki basit veri yapısının sadece teorik kavramlar olmadığını, yazılımın birçok alanında aktif olarak kullanıldığını görmek heyecan vericidir. Benim tecrübelerime göre, bu yapıların pratik uygulamalarını anlamak, sadece kod yazmayı değil, aynı zamanda sistemlerin nasıl çalıştığını da anlamanıza yardımcı olur.
Yığın (Stack) Uygulamaları
Yığın yapısının LIFO prensibi, özellikle bir şeyleri “geri alma” veya “sırayla işleme” senaryolarında çok kullanışlıdır:
- Fonksiyon Çağrı Yönetimi: Programlama dillerinin çoğu, fonksiyon çağrılarını yönetmek için dahili olarak yığınları kullanır. Bir fonksiyon başka bir fonksiyonu çağırdığında, çağıran fonksiyonun durumu (değişkenleri, geri dönüş adresi vb.) yığına atılır (push). Çağrılan fonksiyon işini bitirince, yığının en üstündeki durum alınır (pop) ve çağıran fonksiyona geri dönülür. Bu mekanizma, iç içe fonksiyon çağrılarının doğru sırayla yönetilmesini sağlar.
- Geri Al (Undo) ve Yinele (Redo) İşlemleri: Metin editörleri, grafik programları veya veritabanı sistemleri gibi birçok uygulamada “Geri Al” özelliği bulunur. Yaptığınız her işlem bir yığına eklenir. “Geri Al” dediğinizde yığının en üstündeki son işlem çıkarılır ve tersi yapılır. “Yinele” özelliği ise genellikle ayrı bir yığınla yönetilir.
- İfade Değerlendirmesi: Matematiksel veya mantıksal ifadelerin (örneğin, 3 + (4 * 2) – 1) bilgisayar tarafından doğru öncelik sırasıyla değerlendirilmesinde yığınlar kullanılır. Operatörlerin ve operandların işlenme sırası yığın yardımıyla takip edilir.
Kuyruk (Queue) Uygulamaları
Kuyruk yapısının FIFO prensibi ise, işlerin sırayla ve adil bir şekilde işlenmesi gereken durumlarda idealdir:
- Yazıcı Kuyrukları: Bir ağdaki yazıcıya birden fazla kişi aynı anda yazdırma emri gönderdiğinde, bu emirler bir kuyruğa alınır ve yazıcı bu işleri sırayla (ilk gelene ilk hizmet) işler.
- Görev Zamanlama (Task Scheduling): İşletim sistemleri, çalışan veya çalışmaya hazır olan işlemleri yönetmek için kuyrukları kullanır. İşlemciye (CPU) erişim bekleyen işlemler bir kuyrukta tutulur ve işlemci sıradaki ilk işi alır.
- Web Sunucusu İstekleri: Bir web sunucusu, aynı anda birçok kullanıcıdan istek alabilir. Bu istekler bir kuyruğa alınır ve sunucu bu istekleri sırayla işleyerek aşırı yüklenmeyi önler.
- Genişlik-Öncelikli Arama (BFS – Breadth-First Search) Algoritması: Graf (graph) veri yapılarında düğümleri katman katman gezmek için kullanılan BFS algoritması, hangi düğümleri ziyaret edeceğini takip etmek için kuyruk yapısını kullanır.
Bu Yapıların Avantajları Nelerdir? Neden Önemliler?
Yığın ve kuyruk gibi temel veri yapılarının neden hala bu kadar çok yerde kullanıldığını anlamak, onların sunduğu avantajları görmekten geçer. Benim gözümde, bu yapıların en büyük gücü, basit olmalarına rağmen çok çeşitli ve karmaşık problemleri çözmek için sağlam bir temel sunmalarıdır.
Yığının (Stack) Avantajları
- Basitlik ve Verimlilik: LIFO prensibi sayesinde ekleme ve çıkarma (Push/Pop) işlemleri genellikle çok hızlıdır (O(1) zaman karmaşıklığı). Bu, özellikle performansın önemli olduğu yerlerde avantaj sağlar.
- Hafıza Yönetimi Kolaylığı: Fonksiyon çağrı yığını gibi kullanımlarda, hafıza alanı ayrılması ve serbest bırakılması otomatik ve düzenli bir şekilde gerçekleşir.
- Doğal Yapı: Geri alma, ifade değerlendirme gibi bazı problemlerin doğası gereği yığın yapısına çok iyi uyması, çözüm geliştirmeyi kolaylaştırır.
- Özyinelemeli (Recursive) Algoritmalar: Özyinelemeli fonksiyonlar dahili olarak yığın yapısını kullanır. Yığını anlamak, özyinelemeyi daha iyi kavramanıza yardımcı olur.
Kuyruğun (Queue) Avantajları
- Düzenli İşlem Akışı: FIFO prensibi, işlemlerin veya verilerin alındığı sırayla işlenmesini garanti eder. Bu, adil kaynak dağılımı veya işlem sırası gerektiren senaryolarda kritiktir.
- Senkronizasyon ve Tamponlama: Farklı hızlarda çalışan sistem bileşenleri arasında veri akışını düzenlemek için tampon (buffer) görevi görür. Verinin üretildiği hız ile tüketildiği hız farklı olsa bile, kuyruk sayesinde sistem kararlı kalır.
- Kaynak Yönetimi: İşletim sistemleri gibi karmaşık sistemlerde, kısıtlı kaynaklara (CPU, yazıcı vb.) erişimi adil bir şekilde yönetmek için kullanılır.
- Asenkron İletişim: Bir bileşenin işini bitirmesini beklemeden diğerinin devam etmesini sağlayan asenkron sistemlerde, kuyruklar mesajların veya görevlerin güvenli bir şekilde iletilmesini sağlar.
- Yük Dengeleme: Gelen iş yükünü (sunucu istekleri gibi) birden fazla işlemci veya sunucuya dağıtmak için kullanılabilir.
Sıkça Sorulan Sorular (SSS)
Bu konu hakkında sıkça karşılaştığım bazı sorular ve cevapları:
Yığın ve kuyruk arasındaki temel fark nedir?
Temel fark, elemanların işlenme sırasındadır. Yığın Son Giren İlk Çıkar (LIFO) prensibiyle çalışırken, kuyruk İlk Giren İlk Çıkar (FIFO) prensibini takip eder. Yani yığında en son eklenen ilk çıkar, kuyrukta ise ilk eklenen ilk çıkar.
Bir veri yapısı hem yığın hem de kuyruk gibi davranabilir mi?
Evet, Deque (Double-Ended Queue – Çift Uçlu Kuyruk) adı verilen bir veri yapısı hem yığının hem de kuyruğun özelliklerini taşır. Deque’nin hem başından hem de sonundan eleman ekleyip çıkarabilirsiniz. Bu esneklik, onu bazı algoritmalar için kullanışlı hale getirir.
Ne zaman yığın kullanmalıyım?
Yığın, en son eklenen elemanların öncelikli olarak işlenmesi gereken durumlarda kullanılır. Fonksiyon çağrıları, geri alma/yineleme özellikleri veya ifadelerin işlenmesi gibi LIFO mantığına uyan senaryolar için yığın idealdir.
Ne zaman kuyruk kullanmalıyım?
Kuyruk, elemanların eklenme sırasına göre işlenmesi gereken durumlarda tercih edilir. Yazıcı işleri, görev zamanlama, mesaj kuyrukları veya BFS algoritması gibi FIFO mantığına uyan senaryolar için kuyruk kullanılır.
Yığın ve kuyruk kullanmanın herhangi bir sınırlaması var mı?
Temel (dizi tabanlı) uygulamalarda sabit boyutlu olabilirler, bu da aşırı yüklenme (overflow) veya boşalma (underflow) durumlarına yol açabilir. Ancak, dinamik olarak boyutlanabilen (bağlı liste tabanlı) yığın ve kuyruk uygulamaları bu sınırlamayı ortadan kaldırır.
Yığın ve kuyruk üzerine inşa edilen daha gelişmiş veri yapıları nelerdir?
Öncelik kuyrukları (Priority Queue – elemanların önceliğe göre işlendiği kuyruk), Deque (çift uçlu kuyruk) ve bazı özel algoritmalar için kullanılan yığın varyasyonları (örneğin, minimum elemanı hızlıca bulabilen yığın) bu temel yapıların üzerine inşa edilir.
Son Olarak: Neden Bu Temelleri Bilmek Şart?
Anlayacağınız üzere, yığın ve kuyruk arasındaki farkı ve hangi senaryoda hangisini kullanacağınızı bilmek, yazılım geliştirme sürecinde size önemli avantajlar sağlar. Bu yapılar, daha karmaşık algoritmaları ve sistem tasarımlarını anlamanın ve uygulamanın ilk adımıdır. LIFO ve FIFO prensiplerini kavramak, sadece bu iki yapıyı değil, genel olarak veri akışını ve işlem yönetimini düşünme biçiminizi şekillendirir.
Yazılımcılık sürekli öğrenme gerektiren bir alan ve bu temel veri yapıları, bu yolculuğun vazgeçilmez bir parçasıdır. Bu yazıda öğrendiklerinizle birlikte, artık kod yazarken veya var olan sistemleri incelerken yığın ve kuyruk mantığını daha kolay fark edeceksiniz. faikylmz.com‘daki diğer yazılarımla yazılım bilginizi derinleştirmeye devam edebilirsiniz.