
Kuyruk Veri Yapısı Açıklandı
Kuyruk, İlk Giren İlk Çıkar (FIFO) prensibini takip eden doğrusal bir veri yapısıdır. Bu, kuyruğa ilk eklenen öğenin, kuyruktan ilk kaldırılan öğe olduğu anlamına gelir.
Kuyruklar, bilgisayar bilimlerinde ve yazılım mühendisliğinde çok önemlidir. Görev zamanlama, yazıcı kuyrukları, mesaj kuyrukları, istek işleme, genişlik öncelikli arama (BFS), arka plan işleri, işletim sistemleri ve birçok gerçek yazılım sisteminde kullanılırlar.
Giriş
Veri yapıları, geliştiricilerin verileri nasıl erişileceği ve işleneceği doğrultusunda düzenlemelerine yardımcı olur. Diziler, bağlı listeler, yığınlar, kuyruklar, ağaçlar, grafikler ve hash tabloları farklı erişim modellerini destekler.
Kuyruk, bekleme hatlarını modellediği için en pratik veri yapılarından biridir. Kuyruğa ilk giren öğe, ilk ayrılan öğe olmalıdır. Bu davranış, gerçek hayatta ve yazılım sistemlerinde yaygındır.
Örneğin, bir hizmet masasında bekleyen müşteriler genellikle geliş sırasına göre hizmet alırlar. Bir yazıcı, belgeleri gönderildikleri sıraya göre işler. Bir sunucu, istekleri geldikleri sıraya göre işleyebilir. Bunların hepsi kuyruk benzeri davranışlardır.
Kuyruk Nedir?
Kuyruk, öğelerin bir uçtan eklendiği ve diğer uçtan kaldırıldığı bir öğe koleksiyonudur.
Öğelerin eklendiği uca genellikle kuyruğun arkası (rear) denir. Öğelerin kaldırıldığı uca ise kuyruğun önü (front) denir.
Kuyruk, FIFO kuralını takip eder:
First In, First OutBu, en uzun süre beklemiş öğenin ilk işleneceği anlamına gelir.
Ana fikir basittir:
Yeni öğeleri arkadan ekleyin.
Öğeleri önden kaldırın.
Gerektiğinde ön öğeyi kaldırmadan okuyun.
Bir öğeyi kaldırmadan önce kuyruğun boş olup olmadığını kontrol edin.
Kuyruk, sıralı işleme için tasarlanmıştır, rastgele erişim için değil.
Kuyruğun Gerçek Hayat Benzetmesi
Kuyruğun yaygın bir gerçek hayat örneği, bir kasada bekleyen insanlardır.
Front → Person A → Person B → Person C ← RearA Kişisi ilk geldi, bu yüzden A Kişisi ilk hizmet alır. C Kişisi son geldi, bu yüzden C Kişisi diğerlerinin arkasında bekler.
Yeni bir kişi gelirse, arkadan katılır:
Front → Person A → Person B → Person C → Person D ← RearKasiyer birine hizmet verdiğinde, A Kişisi ilk ayrılır:
Front → Person B → Person C → Person D ← RearProgramlamada bir Kuyruk tam olarak böyle çalışır.
FIFO Prensibi
FIFO, İlk Giren İlk Çıkar anlamına gelir. Bu, kuyruğa ilk eklenen öğenin, kuyruktan ilk kaldırılan öğe olduğu anlamına gelir.
Örneğin, değerleri bu sırayla kuyruğa eklersek (enqueue):
10, 20, 30Kuyruk şöyle görünür:
Front → 10 → 20 → 30 ← RearBir öğeyi kuyruktan çıkarırsak (dequeue), 10 değeri ilk kaldırılır çünkü kuyruğa ilk giren oydu.
Bu davranış, Son Giren İlk Çıkar (LIFO) prensibini takip eden Yığın'dan (Stack) farklıdır.
Temel Kuyruk İşlemleri
Bir Kuyruk genellikle küçük bir grup önemli işlemi destekler.
enqueue (kuyruğa ekle): Kuyruğun arkasına bir öğe ekler.
dequeue (kuyruktan çıkar): Ön öğeyi kaldırır ve döndürür.
front (ön): Ön öğeyi kaldırmadan döndürür.
rear (arka): Arka öğeyi kaldırmadan döndürür.
isEmpty (boş mu): Kuyrukta hiç öğe olup olmadığını kontrol eder.
size (boyut): Kuyruktaki öğe sayısını döndürür.
Bu işlemler, öğelerin geliş sırasına göre işlenmesi gerektiğinde Kuyrukları kullanışlı hale getirir.
Enqueue İşlemi
Enqueue işlemi, kuyruğun arkasına yeni bir öğe ekler.
Kuyruk boşsa ve 10'u kuyruğa eklersek, kuyruk şöyle olur:
Front → 10 ← Rear20'yi kuyruğa eklersek, kuyruk şöyle olur:
Front → 10 → 20 ← Rear30'u kuyruğa eklersek, kuyruk şöyle olur:
Front → 10 → 20 → 30 ← RearHer yeni öğe, mevcut arka öğeden sonra eklenir.
Dequeue İşlemi
Dequeue işlemi, kuyruğun önündeki öğeyi kaldırır ve döndürür.
Şu kuyruğu ele alalım:
Front → 10 → 20 → 30 ← RearDequeue'u çağırırsak, 10 değeri kaldırılır.
Removed: 10Kuyruk şöyle olur:
Front → 20 → 30 ← RearTekrar dequeue çağırırsak, 20 değeri kaldırılır.
Removed: 20Kuyruk şöyle olur:
Front → 30 ← RearDequeue işlemi, kuyruk boşken dikkatli kullanılmalıdır. Boş bir kuyruktan kaldırma işlemine genellikle kuyruk taşması (queue underflow) denir.
Front İşlemi
Front işlemi, kuyruktaki ilk öğeyi kaldırmadan döndürür.
Şu kuyruğu ele alalım:
Front → 10 → 20 → 30 ← RearFront'u çağırırsak, sonuç şudur:
10Kuyruk değişmeden kalır:
Front → 10 → 20 → 30 ← RearBu işlem, işlenecek bir sonraki öğeyi incelememiz gerektiğinde kullanışlıdır.
Rear İşlemi
Rear işlemi, kuyruktaki son öğeyi kaldırmadan döndürür.
Şu kuyruğu ele alalım:
Front → 10 → 20 → 30 ← RearRear'ı çağırırsak, sonuç şudur:
30Kuyruk değişmeden kalır.
Rear, en son eklenen öğeyi incelememiz gerektiğinde kullanışlıdır.
isEmpty İşlemi
isEmpty işlemi, kuyrukta herhangi bir öğe olup olmadığını kontrol eder.
Kuyrukta hiç öğe yoksa:
[]Bu durumda isEmpty, true döndürür.
Kuyruk öğeler içeriyorsa:
[10, 20, 30]Bu durumda isEmpty, false döndürür.
Bu işlem, dequeue, front veya rear çağırmadan önce önemlidir.
Manuel Çalıştırma Örneği
Kuyruk işlemlerinin bir dizisini manuel olarak çalıştıralım.
enqueue(10)
enqueue(20)
enqueue(30)
front()
dequeue()
enqueue(40)
dequeue()
rear()Boş bir kuyrukla başlıyoruz:
Queue: []Adım 1: enqueue(10)
10'u kuyruğun arkasına ekleriz.
Front → 10 ← RearAdım 2: enqueue(20)
20'yi 10'dan sonra ekleriz.
Front → 10 → 20 ← RearAdım 3: enqueue(30)
30'u 20'den sonra ekleriz.
Front → 10 → 20 → 30 ← RearAdım 4: front()
Ön öğe 10'dur.
front() returns 10Kuyruk değişmez:
Front → 10 → 20 → 30 ← RearAdım 5: dequeue()
Ön öğe 10 kaldırılır.
dequeue() returns 10Kuyruk şöyle olur:
Front → 20 → 30 ← RearAdım 6: enqueue(40)
40'ı arkaya ekleriz.
Front → 20 → 30 → 40 ← RearAdım 7: dequeue()
Ön öğe 20 kaldırılır.
dequeue() returns 20Kuyruk şöyle olur:
Front → 30 → 40 ← RearAdım 8: rear()
Arka öğe 40'tır.
rear() returns 40Kuyruk değişmeden kalır:
Front → 30 → 40 ← RearBu manuel çalıştırma, FIFO davranışını açıkça gösterir. İlk eklenen değer, ilk kaldırılan değerdir.
Dizi Kullanarak Kuyruk Uygulaması
Bir Kuyruk, bir dizi kullanılarak uygulanabilir. En basit yaklaşım, öğeleri dizinin sonuna eklemek ve baştan kaldırmaktır.
Örneğin:
[10, 20, 30]10 değeri ön, 30 değeri ise arkadır.
Ancak, bir dizinin başından kaldırma işlemi bazı dillerde verimsiz olabilir çünkü kalan öğelerin kaydırılması gerekebilir. Daha iyi bir uygulama, her dequeue işleminde kaydırmayı önlemek için bir ön indeks kullanır.
Kuyruk Sözde Kodu
class Queue:
items = empty array
frontIndex = 0
enqueue(value):
add value to end of items
dequeue():
if queue is empty:
return error
value = items[frontIndex]
frontIndex = frontIndex + 1
return value
front():
if queue is empty:
return error
return items[frontIndex]
isEmpty():
return frontIndex >= length of items
size():
return length of items - frontIndexBu sürüm, öğeleri doğrudan dizinin başından kaldırmayı önler.
PHP'de Kuyruk Örneği
İşte bir dizi ve bir ön indeks kullanarak Kuyruğun temiz bir PHP uygulaması.
<?php
class Queue
{
private array $items = [];
private int $frontIndex = 0;
public function enqueue(mixed $value): void
{
$this->items[] = $value;
}
public function dequeue(): mixed
{
if ($this->isEmpty()) {
throw new RuntimeException('Cannot dequeue from an empty queue.');
}
$value = $this->items[$this->frontIndex];
$this->frontIndex++;
return $value;
}
public function front(): mixed
{
if ($this->isEmpty()) {
throw new RuntimeException('Cannot read front from an empty queue.');
}
return $this->items[$this->frontIndex];
}
public function rear(): mixed
{
if ($this->isEmpty()) {
throw new RuntimeException('Cannot read rear from an empty queue.');
}
return $this->items[count($this->items) - 1];
}
public function isEmpty(): bool
{
return $this->frontIndex >= count($this->items);
}
public function size(): int
{
return count($this->items) - $this->frontIndex;
}
}
$queue = new Queue();
$queue->enqueue(10);
$queue->enqueue(20);
$queue->enqueue(30);
echo $queue->front(); // 10
echo PHP_EOL;
echo $queue->dequeue(); // 10
echo PHP_EOL;
$queue->enqueue(40);
echo $queue->rear(); // 40Bu uygulama, büyük diziler için verimsiz olabilen array_shift kullanmaktan kaçınır çünkü dahili olarak öğeleri kaydırabilir.
JavaScript'te Kuyruk Örneği
İşte bir dizi ve bir ön indeks kullanan bir JavaScript uygulaması.
class Queue {
constructor() {
this.items = [];
this.frontIndex = 0;
}
enqueue(value) {
this.items.push(value);
}
dequeue() {
if (this.isEmpty()) {
throw new Error('Cannot dequeue from an empty queue.');
}
const value = this.items[this.frontIndex];
this.frontIndex++;
return value;
}
front() {
if (this.isEmpty()) {
throw new Error('Cannot read front from an empty queue.');
}
return this.items[this.frontIndex];
}
rear() {
if (this.isEmpty()) {
throw new Error('Cannot read rear from an empty queue.');
}
return this.items[this.items.length - 1];
}
isEmpty() {
return this.frontIndex >= this.items.length;
}
size() {
return this.items.length - this.frontIndex;
}
}
const queue = new Queue();
queue.enqueue(10);
queue.enqueue(20);
queue.enqueue(30);
console.log(queue.front()); // 10
console.log(queue.dequeue()); // 10
queue.enqueue(40);
console.log(queue.rear()); // 40Bu JavaScript sürümü, her dequeue için shift() kullanmaktan kaçınır. shift() kullanmak daha az verimli olabilir çünkü tüm kalan öğeleri hareket ettirebilir.
Bağlı Liste Kullanarak Kuyruk Uygulaması
Bir Kuyruk, Bağlı Liste kullanılarak da uygulanabilir. Bu uygulamada, kuyruk hem ön referansını hem de arka referansını korur.
Ön, bir sonraki kaldırılacak düğümü işaret eder. Arka ise yeni öğelerin eklendiği düğümü işaret eder.
Front → [10] → [20] → [30] ← RearHem ön hem de arka referanslarıyla, enqueue ve dequeue işlemleri O(1) olabilir.
JavaScript'te Bağlı Liste Kuyruk Örneği
class QueueNode {
constructor(data) {
this.data = data;
this.next = null;
}
}
class LinkedListQueue {
constructor() {
this.frontNode = null;
this.rearNode = null;
this.length = 0;
}
enqueue(value) {
const newNode = new QueueNode(value);
if (this.rearNode === null) {
this.frontNode = newNode;
this.rearNode = newNode;
} else {
this.rearNode.next = newNode;
this.rearNode = newNode;
}
this.length++;
}
dequeue() {
if (this.isEmpty()) {
throw new Error('Cannot dequeue from an empty queue.');
}
const removedValue = this.frontNode.data;
this.frontNode = this.frontNode.next;
if (this.frontNode === null) {
this.rearNode = null;
}
this.length--;
return removedValue;
}
front() {
if (this.isEmpty()) {
throw new Error('Cannot read front from an empty queue.');
}
return this.frontNode.data;
}
rear() {
if (this.isEmpty()) {
throw new Error('Cannot read rear from an empty queue.');
}
return this.rearNode.data;
}
isEmpty() {
return this.frontNode === null;
}
size() {
return this.length;
}
}Bu bağlı liste tabanlı uygulama, kaydırma veya indeks hareketi gerektirmediği için verimlidir.
Dizi Kuyruğu ve Bağlı Liste Kuyruğu Karşılaştırması
Hem diziler hem de bağlı listeler bir Kuyruk uygulamak için kullanılabilir.
Dizi tabanlı bir kuyruk, özellikle üst düzey dillerde basit ve kullanışlıdır. Bağlı liste tabanlı bir kuyruk ise öğeleri kaydırma endişesi duymadan verimli dinamik ekleme ve çıkarma istediğimizde kullanışlıdır.
Başlıca farklılıklar şunlardır:
Dizi kuyruğunun uygulanması kolaydır.
Bağlı liste kuyruğu düğümler ve referanslar kullanır.
Dizi kuyruğu, maliyetli ön kaldırma işlemlerinden kaçınmalıdır.
Bağlı liste kuyruğu, ön ve arka referanslarla O(1) enqueue ve dequeue işlemlerini destekleyebilir.
Dizi kuyruğu, ön indeks sürekli artarsa kullanılmayan alan bırakabilir.
Bağlı liste kuyruğu, düğüm referansları için ekstra bellek kullanır.
Öğrenmek için her iki uygulama da kullanışlıdır. Üretim için ise yerleşik kuyruk yapıları veya optimize edilmiş kütüphaneler daha iyi olabilir.
Kuyruk Türleri
Birçok Kuyruk türü vardır. Her tür, farklı bir problemi çözer.
Başlıca türler şunlardır:
Basit Kuyruk.
Dairesel Kuyruk.
Öncelikli Kuyruk.
Çift Uçlu Kuyruk (Deque).
Bu türleri anlamak, geliştiricilerin farklı durumlar için doğru kuyruk yapısını seçmelerine yardımcı olur.
Basit Kuyruk
Basit Kuyruk, normal FIFO kuralını takip eder. Öğeler arkadan eklenir ve önden kaldırılır.
Front → 10 → 20 → 30 ← RearBu, çoğu başlangıç örneğinde kullanılan standart kuyruktur.
Basit Kuyruklar şunlar için kullanışlıdır:
Temel görev işleme.
İstek işleme.
Sıraya dayalı işleme.
FIFO davranışını öğretme.
Dairesel Kuyruk
Dairesel Kuyruk, kuyruğun sonunu mantıksal olarak başına bağlar. Genellikle sabit boyutlu bir dizi kullanılarak uygulanır.
Ana fikir, arka dizinin sonuna ulaştığında, boş alan varsa başına dönebilmesidir (wrap around).
Array size: 5
[_, 20, 30, 40, _]
front rearBaşlangıçta yer varsa, arka oraya geçebilir:
[50, 20, 30, 40, _]
rear frontDairesel Kuyruklar, sabit boyutlu tamponlar, akış verileri ve işletim sistemi zamanlaması ile çalışırken kullanışlıdır.
Öncelikli Kuyruk
Öncelikli Kuyruk, öğeleri geliş sırasına göre değil, önceliğe göre kaldırır.
Örneğin, bir hastane acil durum sisteminde, kritik bir hasta, daha önce gelmiş ancak durumu daha az acil olan birinden önce tedavi edilebilir.
Task A: priority 2
Task B: priority 5
Task C: priority 1Daha yüksek öncelikli değerler önce işlenirse, Görev B, Görev A ve Görev C'den önce kaldırılır.
Öncelikli Kuyruklar genellikle heap (yığın) kullanılarak uygulanır, çünkü heap'ler en yüksek veya en düşük öncelikli öğenin verimli bir şekilde eklenmesini ve kaldırılmasını sağlar.
Çift Uçlu Kuyruk (Deque)
Deque (çift uçlu kuyruk olarak telaffuz edilir), her iki uçtan da ekleme ve kaldırma işlemlerine izin verir.
Front ⇄ [10] ⇄ [20] ⇄ [30] ⇄ RearBir Deque, nasıl kullanıldığına bağlı olarak bir Kuyruk veya bir Yığın gibi davranabilir.
Deque işlemleri şunları içerir:
Önden ekle.
Arkadan ekle.
Önden kaldır.
Arkadan kaldır.
Deque'ler, kayan pencere algoritmalarında, geri al-yinele sistemlerinde ve gelişmiş zamanlama problemlerinde kullanışlıdır.
Kuyruk İşlemlerinin Zaman Karmaşıklığı
Zaman karmaşıklığı, bir işlemin çalışma süresinin öğe sayısı arttıkça nasıl büyüdüğünü açıklar.
İyi bir uygulamaya sahip standart bir Kuyruk için yaygın karmaşıklıklar şunlardır:
enqueue: O(1)
dequeue: O(1)
front: O(1)
rear: O(1)
isEmpty: O(1)
size: O(1)
search (arama): O(n)
Kuyruk doğru uygulandığında enqueue ve dequeue sabit zamanlı işlemlerdir.
Enqueue Neden O(1)dir?
Enqueue işlemi, kuyruğun arkasına yeni bir öğe ekler.
Before:
Front → 10 → 20 ← Rear
enqueue(30)
After:
Front → 10 → 20 → 30 ← RearArka konum biliniyorsa, yeni öğeyi eklemek tüm kuyruğu taramayı gerektirmez.
Bu nedenle, enqueue:
O(1)Dequeue Neden O(1)dir?
Dequeue işlemi, ön öğeyi kaldırır.
Before:
Front → 10 → 20 → 30 ← Rear
dequeue()
After:
Front → 20 → 30 ← RearÖn konum biliniyorsa, ön öğeyi kaldırma doğrudan yapılabilir.
Bu nedenle, dequeue:
O(1)Bu, iyi bir uygulama olduğunu varsayar. Bir dizi uygulaması her seferinde maliyetli bir kaydırma işlemi kullanıyorsa, dequeue O(n) haline gelebilir.
Arama Neden O(n)dir?
Bir Kuyruk içinde arama yapmak yapının ana amacı değildir. Belirli bir değeri bulmamız gerekirse, öğeleri tek tek incelememiz gerekebilir.
Front → 10 → 20 → 30 ← Rear30'u aramak için önce 10'u, sonra 20'yi, sonra 30'u kontrol etmemiz gerekebilir.
En kötü durumda, tüm öğeler kontrol edilir, bu nedenle arama:
O(n)Kuyruğun Uzay Karmaşıklığı
Bir Kuyruğun uzay karmaşıklığı O(n)'dir, burada n kuyrukta depolanan öğe sayısıdır.
Kuyruk 100 öğe depoluyorsa, 100 öğe için belleğe ihtiyaç duyar. 1.000 öğe depoluyorsa, 1.000 öğe için belleğe ihtiyaç duyar.
Space complexity = O(n)Kuyruk bağlı düğümler kullanılarak uygulanıyorsa, her düğüm bir sonraki düğüme bir referans da depolar. Bir dizi kullanılarak uygulanıyorsa, bellek dizi kapasitesine ve uygulama stratejisine bağlıdır.
Kuyruk Taşması ve Kuyruk Altı Taşması
Kuyruk taşması (queue overflow), bir kuyruğun sabit bir kapasitesi olduğunda ve bir programın kuyruğun tutabileceğinden daha fazla öğe eklemeye çalıştığında meydana gelir.
Queue capacity: 3
Queue: [10, 20, 30]
enqueue(40) → overflowKuyruk altı taşması (queue underflow), bir programın boş bir kuyruktan bir öğeyi kaldırmaya veya okumaya çalıştığında meydana gelir.
Queue: []
dequeue() → underflowİyi Kuyruk uygulamaları, bir istisna fırlatarak, null döndürerek veya açık bir hata stratejisi kullanarak bu durumları güvenli bir şekilde ele almalıdır.
Kuyruklar ve Genişlik Öncelikli Arama (BFS)
Bir Kuyruğun en önemli algoritmik kullanımlarından biri Genişlik Öncelikli Arama (Breadth-First Search) veya bilinen adıyla BFS'tir.
BFS, düğümleri seviye seviye keşfeder. Bir Kuyruk, hangi düğümün bir sonraki işleneceğini hatırlamak için kullanılır.
Örneğin, bir grafikte veya ağaçta:
Start with node A
enqueue(A)
While queue is not empty:
dequeue a node
visit it
enqueue its unvisited neighborsFIFO davranışı, daha önce keşfedilen düğümlerin daha erken işlenmesini sağlar ve bu da seviye sırasına göre geçiş (level-order traversal) oluşturur.
Kuyruklar ve Görev Zamanlama
Kuyruklar, görevlerin geliş sırasına göre işlenmesi gereken görev zamanlama sistemlerinde kullanılır.
Örneğin:
Task 1: Send email
Task 2: Generate report
Task 3: Resize imageBir çalışan, kuyruğun önündeki görevleri işleyebilir:
dequeue() → Send email
dequeue() → Generate report
dequeue() → Resize imageBu model, arka plan iş sistemlerinde ve mesaj aracıları (message brokers) arasında yaygındır.
Kuyruklar ve Yazıcı İşleri
Bir yazıcı kuyruğu, klasik bir Kuyruk örneğidir. Üç belge bir yazıcıya gönderilirse, genellikle geldikleri sıraya göre yazdırılırlar.
Front → Document A → Document B → Document C ← RearBelge A önce, sonra Belge B, sonra Belge C yazdırılır.
Bu, gerçek bir sistemde FIFO davranışıdır.
Kuyruklar ve Web İstekleri
Kuyruklar web sistemlerinde de kullanılır. Çok sayıda istek veya arka plan işi geldiğinde, bir kuyruk bunları çalışanlar işlemeye hazır olana kadar tutabilir.
Örneğin, bir Laravel uygulaması kuyrukları şunlar için kullanabilir:
E-posta gönderme.
Yüklenen dosyaları işleme.
Rapor oluşturma.
Bildirim gönderme.
Yavaş görevleri arka planda çalıştırma.
Bu, yavaş işlemlerin ana kullanıcı isteğini engellemesini önler.
Pratik Örnek: JavaScript'te Basit Görev Kuyruğu
İşte basit bir görev kuyruğu örneği:
class TaskQueue {
constructor() {
this.queue = [];
this.frontIndex = 0;
}
addTask(task) {
this.queue.push(task);
}
processTask() {
if (this.frontIndex >= this.queue.length) {
return null;
}
const task = this.queue[this.frontIndex];
this.frontIndex++;
return task;
}
}
const tasks = new TaskQueue();
tasks.addTask('Send email');
tasks.addTask('Generate report');
tasks.addTask('Resize image');
console.log(tasks.processTask()); // Send email
console.log(tasks.processTask()); // Generate reportEklenen ilk görev, işlenen ilk görevdir.
Kuyruk ve Yığın Karşılaştırması
Kuyruklar ve Yığınlar her ikisi de doğrusal veri yapılarıdır, ancak farklı erişim kurallarını takip ederler.
Bir Kuyruk FIFO'yu takip eder:
First In, First OutBir Yığın LIFO'yu takip eder:
Last In, First OutÖrneğin, bir Kuyruk bekleyen bir insan sırası gibidir. İlk gelen kişi ilk hizmet alır.
Bir Yığın, bir tabak yığını gibidir. Üste konulan son tabak ilk kaldırılır.
Başlıca farklılıklar şunlardır:
Kuyruk en eski öğeyi önce kaldırır.
Yığın en yeni öğeyi önce kaldırır.
Kuyruk enqueue ve dequeue kullanır.
Yığın push ve pop kullanır.
Kuyruk, zamanlama ve bekleme sıraları için kullanışlıdır.
Yığın, geri alma (undo), özyineleme (recursion) ve geri izleme (backtracking) için kullanışlıdır.
Geliştiriciler Kuyruğu Ne Zaman Kullanmalı?
Geliştiriciler, öğelerin geldikleri sırayla işlenmesi gerektiğinde bir Kuyruk kullanmalıdır.
Kuyruklar şunlar için kullanışlıdır:
İlk giren, ilk çıkar davranışı gereklidir.
Görevler geliş sırasına göre işlenmelidir.
İsteklerin işlenmeden önce beklemesi gerekir.
Genişlik öncelikli arama (BFS) gereklidir.
Arka plan işleri kullanılır.
Mesaj işleme gereklidir.
Zamanlama veya tamponlama gereklidir.
Ana sinyal FIFO davranışıdır. En eski öğe önce işlenmeli ise, bir Kuyruk doğru yapı olabilir.
Kuyruk Ne Zaman Kullanılmamalıdır?
En yeni öğe önce işlenmeli veya rastgele erişim gerektiğinde bir Kuyruk doğru yapı değildir.
Geliştiriciler Kuyruktan şunlar olduğunda kaçınmalıdır:
Son giren, ilk çıkar davranışı gereklidir.
İndekse göre hızlı rastgele erişim gereklidir.
Öncelik tabanlı işleme gereklidir.
Sık sık arama yapmak ana işlemdir.
Geliş sırası önemli değildir.
Bu durumlarda, bir Yığın, Dizi, Hash Tablosu, Öncelikli Kuyruk veya başka bir veri yapısı daha uygun olabilir.
Kuyrukları Öğrenirken Sık Yapılan Hatalar
Yeni başlayanlar genellikle FIFO fikrini anlarlar ancak uygulama veya karmaşıklık analizinde hata yaparlar.
Sık yapılan hatalar şunlardır:
Kuyruğu Yığın ile karıştırmak.
Yanlış uçtan kaldırma.
Performansı anlamadan maliyetli dizi kaydırma kullanmak.
Boş kuyruk durumlarını ele almayı unutmak.
Aramanın O(1) olduğunu varsaymak.
Bağlı liste kuyruklarında ön ve arkayı doğru şekilde güncellememek.
Dairesel kuyruklarda yanlış döngü (wrap-around) mantığı oluşturmak.
En güvenli kural basittir: arkadan kuyruğa ekle ve önden kuyruktan çıkar.
Kuyrukları Anlamak İçin Pratik Kontrol Listesi
Gelişmiş veri yapılarına ve grafik algoritmalarına geçmeden önce, geliştiriciler şu soruları yanıtlayabilmelidir:
FIFO ne anlama gelir?
Bir Kuyruğun önü nedir?
Bir Kuyruğun arkası nedir?
Enqueue ne işe yarar?
Dequeue ne işe yarar?
İyi bir uygulamada enqueue ve dequeue neden O(1)'dir?
Kuyruk altı taşması (queue underflow) nedir?
Kuyruk ile Yığın arasındaki fark nedir?
Dairesel Kuyruk nedir?
BFS neden bir Kuyruk kullanır?
Bu sorular netse, geliştirici Kuyrukların ardındaki gerçek mantığı anlamıştır.
Kuyrukların Avantajları
Kuyrukların birkaç önemli avantajı vardır.
Anlamaları basittir.
Doğal olarak FIFO davranışını desteklerler.
Zamanlama ve bekleme sıraları için kullanışlıdırlar.
Enqueue ve dequeue O(1) olabilir.
BFS için temeldirler.
Arka plan iş sistemlerinde ve mesaj işlemede kullanışlıdırlar.
Bu avantajlar, Kuyrukları bilgisayar bilimlerindeki en önemli veri yapılarından biri yapar.
Kuyrukların Dezavantajları
Kuyrukların sınırlamaları da vardır.
Hızlı rastgele erişim sağlamazlar.
Bir Kuyruk içinde arama yapmak O(n)'dir.
LIFO davranışı için uygun değildirler.
Öncelik tabanlı işleme, bunun yerine bir Öncelikli Kuyruk gerektirir.
Dizi tabanlı uygulamalar, verimsiz kaydırmayı önlemek için dikkatlice tasarlanmalıdır.
Bu sınırlamalar normaldir. Sadece Kuyrukların her olası erişim deseni için değil, sıralı işleme için tasarlandığını gösterirler.
Gerçek Yazılım Projelerinde Kuyruklar
Kuyruklar, gerçek yazılım projelerinde birçok biçimde ortaya çıkar. Geliştiriciler, Kuyruk sınıflarını manuel olarak uygulamak yerine yerleşik kuyrukları, mesaj aracılarını, iş sistemlerini veya framework kuyruk araçlarını kullanabilirler.
Yaygın gerçek dünya kullanımları şunlardır:
Arka plan işi işleme.
E-posta gönderme.
Bildirim sistemleri.
Yazıcı işi yönetimi.
İstek tamponlama.
İşletim sistemi zamanlaması.
Mesaj kuyrukları.
Ağaçlarda ve grafiklerde genişlik öncelikli arama (BFS).
Kuyrukları anlamak, geliştiricilerin eşzamansız ve sıralı işleme sistemlerinin dahili olarak nasıl çalıştığını anlamalarına yardımcı olur.
Sonuç
Kuyruk, İlk Giren İlk Çıkar prensibini takip eden doğrusal bir veri yapısıdır. Kuyruğa ilk eklenen öğe, ilk kaldırılan öğedir.
Başlıca Kuyruk işlemleri enqueue, dequeue, front, rear, isEmpty ve size'dır. Enqueue bir öğeyi arkaya eklerken, dequeue ön öğeyi kaldırır.
İyi bir uygulama ile enqueue, dequeue, front, rear, isEmpty ve size O(1) karmaşıklığındadır. Kuyruk içinde arama yapmak O(n)'dir çünkü yapı rastgele erişim için tasarlanmamıştır.
Kuyruklar, diziler veya bağlı listeler kullanılarak uygulanabilir. Ayrıca Dairesel Kuyruk, Öncelikli Kuyruk ve Çift Uçlu Kuyruk (Deque) gibi önemli varyasyonları da vardır.
Veri Yapıları ve Algoritmaları öğrenen geliştiriciler için Kuyruklar temeldir. FIFO davranışını, sıralı işlemeyi, zamanlama mantığını, BFS geçişini ve arka plan işleri, mesaj kuyrukları ve istek işleme gibi birçok gerçek dünya sisteminin temelini öğretirler.

