← Kursa Dön
📄 Text · 10 min

Queue ve Deque

Gerçek hayattaki kuyrukları düşün — banka kuyruğu, market kası, yazıcı kuyruğu. İlk gelen ilk işlenir, son gelen en sona eklenir. Java'daki Queue interface'i tam olarak bu mantığı modelliyor: FIFO (First-In, First-Out).

Deque ise "Double-Ended Queue" — iki uçlu kuyruk. Hem baştan hem sondan ekleme-çıkarma yapabilirsin. Hem kuyruk (FIFO) hem yığın (LIFO — stack) olarak kullanılabilir. İsviçre çakısı gibi.

Queue Interface

Queue, elemanları işlenmek üzere sıraya koyar. Temel operasyonlar iki grupta gelir:

İşlemException fırlatırnull/false döner
Ekleadd(e)offer(e)
Çıkar (ve döndür)remove()poll()
Bak (çıkarmadan)element()peek()
Queue<String> queue = new LinkedList<>();

// Ekleme
queue.offer("Müşteri 1");    // true
queue.offer("Müşteri 2");    // true
queue.offer("Müşteri 3");    // true

// Bakma (çıkarmadan)
System.out.println(queue.peek());   // "Müşteri 1" — ilk eklenen
System.out.println(queue.size());   // 3 — eleman çıkmadı

// Çıkarma
System.out.println(queue.poll());   // "Müşteri 1" — ilk giren ilk çıktı
System.out.println(queue.poll());   // "Müşteri 2"
System.out.println(queue.poll());   // "Müşteri 3"
System.out.println(queue.poll());   // null — kuyruk boş

offer/poll/peek güvenli versiyonlardır — boş kuyruğa poll() çağırırsan null döner. add/remove/element ise hata fırlatır:

Queue<String> queue = new LinkedList<>();

// Boş kuyrukte fark
queue.poll();     // null — güvenli
queue.peek();     // null — güvenli
queue.remove();   // NoSuchElementException!
queue.element();  // NoSuchElementException!

💡 İpucu: Her zaman offer/poll/peek üçlüsünü tercih et. Exception fırlatan versiyonları sadece "kuyruk boşsa bu bir bug'dır" durumlarında kullan.

Deque Interface

Deque (Double-Ended Queue), hem baştan hem sondan erişim sağlar:

   addFirst ←  [A] [B] [C] [D]  → addLast
removeFirst ←  [A] [B] [C] [D]  → removeLast
   getFirst →  [A]           [D]  ← getLast
Deque<String> deque = new ArrayDeque<>();

// Başa ekleme
deque.addFirst("B");
deque.addFirst("A");     // [A, B]

// Sona ekleme
deque.addLast("C");
deque.addLast("D");      // [A, B, C, D]

// Baştan çıkarma
deque.removeFirst();      // "A" → [B, C, D]

// Sondan çıkarma
deque.removeLast();       // "D" → [B, C]

// Başa ve sona bakma
deque.peekFirst();        // "B"
deque.peekLast();         // "C"

Deque'nin güvenli ve exception fırlatan method'ları:

İşlemException fırlatırnull/false döner
Başa ekleaddFirst(e)offerFirst(e)
Sona ekleaddLast(e)offerLast(e)
Baştan çıkarremoveFirst()pollFirst()
Sondan çıkarremoveLast()pollLast()
Başa bakgetFirst()peekFirst()
Sona bakgetLast()peekLast()

LinkedList as Queue

LinkedList hem List hem Queue hem Deque interface'lerini implement eder:

// Queue olarak
Queue<String> queue = new LinkedList<>();
queue.offer("A");
queue.offer("B");
queue.poll(); // "A"

// Deque olarak
Deque<String> deque = new LinkedList<>();
deque.addFirst("A");
deque.addLast("B");

Ama Queue/Deque ihtiyacı için ArrayDeque daha iyi. Neden? Birazdan göreceğiz.

ArrayDeque: Tercih Edilen Implementasyon

ArrayDeque, dairesel dizi (circular array) kullanır. LinkedList'ten neredeyse her senaryoda daha hızlıdır.

// Queue olarak
Deque<Integer> queue = new ArrayDeque<>();
queue.offer(1);
queue.offer(2);
queue.offer(3);
System.out.println(queue.poll()); // 1 (FIFO)
System.out.println(queue.poll()); // 2

// Stack olarak (LIFO)
Deque<Integer> stack = new ArrayDeque<>();
stack.push(1);
stack.push(2);
stack.push(3);
System.out.println(stack.pop()); // 3 (LIFO — son giren ilk çıktı)
System.out.println(stack.pop()); // 2

⚠️ ArrayDeque null kabul etmez. offer(null) → NullPointerException. LinkedList null kabul eder ama Queue olarak kullanırken null değer poll() dönüşüyle karışır.

Neden ArrayDeque > LinkedList (Queue/Deque için)?

ÖzellikArrayDequeLinkedList
BellekDaha az (dizi)Daha çok (node nesneleri)
Cache performansıİyi (ardışık bellek)Kötü (dağınık bellek)
null desteği
Hem Queue hem List❌ (sadece Deque)
// Modern Java'da kuyruk ihtiyacı → ArrayDeque
Deque<String> queue = new ArrayDeque<>();

// Stack ihtiyacı → ArrayDeque (Stack sınıfını KULLANMA)
Deque<String> stack = new ArrayDeque<>();

Deque as Stack

Java'da eski Stack sınıfı var ama kullanma. Synchronized ve Vector tabanlı — yavaş. Deque kullan:

Stack operasyonuDeque karşılığı
push(e)addFirst(e) veya push(e)
pop()removeFirst() veya pop()
peek()peekFirst() veya peek()
// Stack gibi kullanım — LIFO
Deque<String> stack = new ArrayDeque<>();
stack.push("Birinci");     // [Birinci]
stack.push("İkinci");      // [İkinci, Birinci]
stack.push("Üçüncü");     // [Üçüncü, İkinci, Birinci]

System.out.println(stack.pop());  // "Üçüncü" — son giren ilk çıktı
System.out.println(stack.pop());  // "İkinci"
System.out.println(stack.peek()); // "Birinci" — çıkarmadan bak

Gerçek Dünya: İş Kuyruğu

public class TaskQueue {
    private final Deque<Runnable> tasks = new ArrayDeque<>();
    
    public void submit(Runnable task) {
        tasks.offer(task);
    }
    
    public void submitUrgent(Runnable task) {
        tasks.offerFirst(task); // Acil iş başa eklenir
    }
    
    public void processNext() {
        Runnable task = tasks.poll();
        if (task != null) {
            task.run();
        }
    }
    
    public int pendingCount() {
        return tasks.size();
    }
}

Gerçek Dünya: Undo Mekanizması

public class TextEditor {
    private String content = "";
    private final Deque<String> undoStack = new ArrayDeque<>();
    private final Deque<String> redoStack = new ArrayDeque<>();
    
    public void type(String text) {
        undoStack.push(content);  // Mevcut durumu kaydet
        redoStack.clear();         // Redo geçmişini temizle
        content += text;
    }
    
    public void undo() {
        if (!undoStack.isEmpty()) {
            redoStack.push(content);
            content = undoStack.pop();
        }
    }
    
    public void redo() {
        if (!redoStack.isEmpty()) {
            undoStack.push(content);
            content = redoStack.pop();
        }
    }
}
public static void bfs(Map<String, List<String>> graph, String start) {
    Queue<String> queue = new ArrayDeque<>();
    Set<String> visited = new HashSet<>();
    
    queue.offer(start);
    visited.add(start);
    
    while (!queue.isEmpty()) {
        String node = queue.poll();
        System.out.println("Ziyaret: " + node);
        
        for (String neighbor : graph.getOrDefault(node, List.of())) {
            if (!visited.contains(neighbor)) {
                visited.add(neighbor);
                queue.offer(neighbor);
            }
        }
    }
}

Özet

  • Queue FIFO (ilk giren ilk çıkar) yapısı — offer/poll/peek güvenli method'lar, add/remove/element exception fırlatır

  • Deque çift uçlu kuyruk — hem baştan hem sondan ekleme/çıkarma, hem Queue hem Stack olarak kullanılır

  • ArrayDeque neredeyse her zaman LinkedList'ten daha iyi performans verir — Queue/Deque ihtiyacı için ilk tercih

  • Stack sınıfını kullanma — yerine Deque<E> stack = new ArrayDeque<>() ile push/pop yap

  • ArrayDeque null kabul etmez — null lazımsa LinkedList kullan ama genelde null'dan kaçın

  • Queue: iş kuyruğu, BFS. Stack (Deque): undo/redo, DFS, parantez eşleme gibi senaryolarda kullan