Zuletzt aktualisiert am 04.12.2025 5 Minuten Lesezeit

Queue

Queue (deutsch: Warteschlange) ist eine fundamentale Datenstruktur in der Informatik, die nach dem FIFO-Prinzip (First In, First Out) arbeitet. Das bedeutet: Das Element, das zuerst hinzugefügt wurde, wird auch als erstes wieder entnommen. Stell dir eine Queue wie die Warteschlange an einer Supermarktkasse vor - wer zuerst ankommt, wird zuerst bedient.

Funktionsweise einer Queue

Eine Queue hat zwei wichtige Enden: das Front (vorne), wo Elemente entnommen werden, und das Rear oder Back (hinten), wo neue Elemente hinzugefügt werden. Diese klare Trennung garantiert die FIFO-Reihenfolge.

Im Gegensatz zum Stack, der nach dem LIFO-Prinzip (Last In, First Out) funktioniert, verarbeitet eine Queue Elemente in der Reihenfolge ihres Eintreffens. Diese Eigenschaft macht Queues unverzichtbar für viele Anwendungen in der Softwareentwicklung.

Grundlegende Operationen

Jede Queue-Implementierung unterstützt einen standardisierten Satz von Operationen. Diese Operationen bilden die Schnittstelle, über die du mit der Datenstruktur interagierst:

Operation Beschreibung Zeitkomplexität
enqueue(element) Fügt ein Element am Ende (Rear) hinzu O(1)
dequeue() Entfernt und gibt das vorderste Element zurück O(1)
peek() / front() Gibt das vorderste Element zurück, ohne es zu entfernen O(1)
isEmpty() Prüft, ob die Queue leer ist O(1)
size() Gibt die Anzahl der Elemente zurück O(1)

Alle Standardoperationen einer Queue haben eine konstante Zeitkomplexität von O(1). Das bedeutet, dass die Ausführungszeit unabhängig von der Anzahl der gespeicherten Elemente ist - ein wesentlicher Vorteil dieser Datenstruktur.

Implementierung in Java

In Java stellt das Collections Framework das Interface Queue bereit, das von verschiedenen Klassen implementiert wird. Die häufigste Implementierung verwendet LinkedList:

import java.util.LinkedList;
import java.util.Queue;

public class QueueBeispiel {
    public static void main(String[] args) {
        // Queue erstellen
        Queue<String> warteschlange = new LinkedList<>();

        // Elemente hinzufügen (enqueue)
        warteschlange.add("Kunde 1");
        warteschlange.add("Kunde 2");
        warteschlange.add("Kunde 3");

        System.out.println("Queue: " + warteschlange);
        // Ausgabe: Queue: [Kunde 1, Kunde 2, Kunde 3]

        // Erstes Element anschauen (peek)
        System.out.println("Vorne: " + warteschlange.peek());
        // Ausgabe: Vorne: Kunde 1

        // Element entfernen (dequeue)
        String bedient = warteschlange.remove();
        System.out.println("Bedient: " + bedient);
        // Ausgabe: Bedient: Kunde 1

        System.out.println("Verbleibend: " + warteschlange);
        // Ausgabe: Verbleibend: [Kunde 2, Kunde 3]
    }
}

Implementierung in Python

Python bietet mehrere Möglichkeiten, eine Queue zu implementieren. Für performante Anwendungen empfiehlt sich die Verwendung von collections.deque oder das queue-Modul:

from collections import deque

# Queue mit deque erstellen
warteschlange = deque()

# Elemente hinzufügen (enqueue)
warteschlange.append("Auftrag A")
warteschlange.append("Auftrag B")
warteschlange.append("Auftrag C")

print(f"Queue: {list(warteschlange)}")
# Ausgabe: Queue: ['Auftrag A', 'Auftrag B', 'Auftrag C']

# Erstes Element anschauen (peek)
print(f"Nächster Auftrag: {warteschlange[0]}")
# Ausgabe: Nächster Auftrag: Auftrag A

# Element entfernen (dequeue)
bearbeitet = warteschlange.popleft()
print(f"Bearbeitet: {bearbeitet}")
# Ausgabe: Bearbeitet: Auftrag A

# Queue-Status prüfen
print(f"Leer? {len(warteschlange) == 0}")
# Ausgabe: Leer? False

Varianten der Queue

Neben der Standard-Queue gibt es verschiedene Varianten, die für spezifische Anwendungsfälle optimiert sind:

Priority Queue

Bei einer Priority Queue (Prioritätswarteschlange) bestimmt nicht die Ankunftsreihenfolge, sondern die Priorität eines Elements, wann es verarbeitet wird. Elemente mit höherer Priorität werden zuerst entnommen. Dies ist nützlich für Aufgabenplaner oder Algorithmen wie Dijkstras kürzester Weg.

Circular Queue (Ringpuffer)

Ein Ringpuffer ist eine Queue mit fester Größe, bei der das Ende mit dem Anfang verbunden ist. Wenn der Speicher voll ist und ein Element entnommen wurde, kann der freigewordene Platz wiederverwendet werden. Ringpuffer sind besonders effizient für Streaming-Anwendungen und Puffer in Betriebssystemen.

Double-Ended Queue (Deque)

Eine Deque (gesprochen "Deck") erlaubt das Hinzufügen und Entfernen von Elementen an beiden Enden. Sie kombiniert die Eigenschaften von Stack und Queue und bietet damit maximale Flexibilität.

Praktische Anwendungsfälle

Queues sind in der Softwareentwicklung allgegenwärtig. Hier sind einige typische Einsatzgebiete, die du in deiner Ausbildung und später im Beruf antreffen wirst:

  • Druckerwarteschlangen: Druckaufträge werden in der Reihenfolge ihres Eingangs abgearbeitet
  • Task-Scheduling in Betriebssystemen: Prozesse warten auf CPU-Zeit
  • Message Queues: Asynchrone Kommunikation zwischen Anwendungen (z.B. RabbitMQ, Apache Kafka)
  • Webserver: HTTP-Anfragen werden der Reihe nach verarbeitet
  • Breadth-First Search (BFS): Graphenalgorithmus zur Breitensuche
  • Pufferspeicher: Zwischenspeicherung von Datenströmen zwischen schnellen und langsamen Komponenten

Queue vs. Stack

Stack und Queue sind beide lineare Datenstrukturen, unterscheiden sich aber grundlegend in ihrer Zugriffslogik:

Aspekt Queue Stack
Prinzip FIFO (First In, First Out) LIFO (Last In, First Out)
Hinzufügen Am Ende (Rear) Oben (Top)
Entfernen Am Anfang (Front) Oben (Top)
Typische Anwendung Warteschlangen, BFS Funktionsaufrufe, DFS, Undo

Die Wahl zwischen Queue und Stack hängt vom Anwendungsfall ab: Wenn die Reihenfolge des Eintreffens wichtig ist, verwendest du eine Queue. Wenn du immer das zuletzt hinzugefügte Element zuerst verarbeiten möchtest, ist ein Stack die richtige Wahl.

Implementierungsdetails

Eine Queue kann auf verschiedene Weisen implementiert werden. Jede Methode hat ihre Vor- und Nachteile:

Array-basierte Implementierung

Bei der Array-basierten Implementierung werden Elemente in einem Array gespeichert. Der Vorteil ist die gute Cache-Lokalität und der vorhersehbare Speicherverbrauch. Der Nachteil: Bei einfachen Arrays muss beim Entfernen vom Anfang das gesamte Array verschoben werden (O(n)), oder man verwendet einen Ringpuffer.

Verkettete Liste

Bei einer verketteten Liste hat jedes Element einen Zeiger auf das nächste Element. Das Hinzufügen und Entfernen ist immer O(1), allerdings ist der Speicheroverhead durch die Zeiger höher und die Cache-Lokalität schlechter als bei Arrays.

Queue in der Praxis

Als Fachinformatiker für Anwendungsentwicklung wirst du Queues in vielen Kontexten einsetzen. Besonders bei der Entwicklung von Backend-Systemen und der Verarbeitung von Anfragen sind Queues unverzichtbar. Auch in der Systemintegration begegnen dir Queues bei Message Brokern und der Kommunikation zwischen verteilten Systemen.

Quellen und weiterführende Links