C# Queue und Stack einfach erklärt: So nutzt du sie richtig
Queue (FIFO) und Stack (LIFO) in C# erklärt: Methoden, Unterschiede und praktische Beispiele für Azubis, Studenten und Berufseinsteiger.
By Marcel Schmidtpeter 30 Sept 2026
Stell dir vor, dein Ausbilder gibt dir die Aufgabe, ein kleines Ticketsystem zu bauen: Support-Anfragen sollen in der Reihenfolge bearbeitet werden, in der sie eingehen. Gleichzeitig soll dein Kollege eine Undo-Funktion für ein Textprogramm bekommen - der letzte Arbeitsschritt muss zuerst rückgängig gemacht werden. Zwei Aufgaben, zwei Datenstrukturen: Queue und Stack. Genau um die geht es hier - und darum, wie du beide in C# richtig einsetzt.
Beide gehören zum Namespace `System.Collections.Generic` und sind generische Collections. Wenn du dabei noch nicht sicher bist, wirf zuerst einen Blick in unseren C# Collections Überblick.
Was ist eine Queue in C#?
Eine Queue (Warteschlange) arbeitet nach dem FIFO-Prinzip: *First In, First Out*. Das Element, das als erstes hineinkommt, kommt auch als erstes wieder heraus. Genau wie an der Supermarkt-Kasse - wer zuerst ansteht, wird zuerst abkassiert.
Die beiden wichtigsten Methoden:
`Enqueue(item)`: fügt ein Element am Ende der Schlange an
`Dequeue()`: entnimmt das vorderste Element und entfernt es aus der Schlange
Queue<string> tickets = new Queue<string>();
tickets.Enqueue("Drucker funktioniert nicht");
tickets.Enqueue("Passwort vergessen");
tickets.Enqueue("Monitor flackert");
// Bearbeitung in Eingangsreihenfolge
string erstesTicket = tickets.Dequeue();
Console.WriteLine(erstesTicket); // Drucker funktioniert nichtDazu gibt es `Peek()` - damit schaust du dir das vorderste Element an, ohne es zu entfernen. Praktisch, wenn du erst prüfen willst, ob sich die Bearbeitung lohnt.
Merke: `Dequeue()` entfernt das Element, `Peek()` liefert es nur zurück. Die Queue wird bei `Peek()` nicht verändert.
Was ist ein Stack in C#?
Ein Stack (Stapel) arbeitet nach dem LIFO-Prinzip: *Last In, First Out*. Das zuletzt hinzugefügte Element wird als erstes wieder entnommen. Stell dir einen Stapel Teller vor: Du legst Teller oben drauf und nimmst sie auch oben wieder herunter.
Die wichtigsten Methoden:
`Push(item)`: legt ein Element oben auf den Stapel
`Pop()`: entnimmt das oberste Element und entfernt es vom Stapel
Stack<string> undoSpeicher = new Stack<string>();
undoSpeicher.Push("Text 'Hallo' eingefuegt");
undoSpeicher.Push("Text 'Welt' eingefuegt");
undoSpeicher.Push("Alles fett formatiert");
// Undo: letzter Schritt zuerst
string letzterSchritt = undoSpeicher.Pop();
Console.WriteLine(letzterSchritt); // Alles fett formatiertAuch hier gibt es `Peek()` mit derselben Bedeutung wie bei der Queue: nachschauen, ohne zu entnehmen.
Queue vs. Stack: Der direkte Vergleich
Eigenschaft | `Queue<T>` | `Stack<T>` |
Prinzip | FIFO (First In, First Out) | LIFO (Last In, First Out) |
Hinzufügen | `Enqueue(item)` - hinten | `Push(item)` - oben |
Entnehmen | `Dequeue()` - vorn | `Pop()` - oben |
Anschauen | `Peek()` | `Peek()` |
Typisches Beispiel | Warteschlange, Print-Jobs | Undo/Redo, Browser-History |
Merke: `Queue<T>` = Supermarkt-Kasse (wer zuerst kommt, zahlt zuerst). `Stack<T>` = Tellerstapel (was oben liegt, wird zuerst genommen).
Intern sind beide Klassen als Array implementiert - die Queue als sogenanntes Ringpuffer-Array. `Enqueue`, `Dequeue`, `Push` und `Pop` laufen damit amortisiert in konstanter Zeit O(1). Einen Indexzugriff wie bei `List<T>` gibt es dagegen nicht, und `Contains(item)` sucht linear (O(n)) - bei großen Datenmengen also teuer. Details findest du in der offiziellen Microsoft-Dokumentation zu Queue<T> und Stack<T>. Wenn du wissen willst, wann stattdessen eine `LinkedList` sinnvoll ist, hilft dir unser Artikel zu List vs. LinkedList in C# weiter.
Praxisbeispiel: Ein kleines Ticketsystem mit Queue
Hier ein vollständiges, lauffähiges Beispiel, wie du es etwa in einem Ausbildungsprojekt oder einer Studienaufgabe umsetzen könntest:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Queue<string> warteschlange = new Queue<string>();
// Tickets gehen ein
warteschlange.Enqueue("Ticket #1: Login defekt");
warteschlange.Enqueue("Ticket #2: Drucker offline");
warteschlange.Enqueue("Ticket #3: VPN bricht ab");
Console.WriteLine("Offene Tickets: " + warteschlange.Count);
// Abarbeitung, bis die Schlange leer ist
while (warteschlange.Count > 0)
{
string ticket = warteschlange.Dequeue();
Console.WriteLine("Bearbeite: " + ticket);
}
Console.WriteLine("Offene Tickets: " + warteschlange.Count); // 0
}
}Die Ausgabe:
Offene Tickets: 3
Bearbeite: Ticket #1: Login defekt
Bearbeite: Ticket #2: Drucker offline
Bearbeite: Ticket #3: VPN bricht ab
Offene Tickets: 0Die `while`-Schleife mit `Count > 0` ist das Standardmuster, um eine Queue vollständig zu leeren, ohne dass eine Exception fliegt. Das `T` in `Queue<T>` ist übrigens ein Typparameter - mehr dazu in unserem Artikel zu C# Generics.
Welche typischen Fehler passieren bei Queue und Stack?
Drei Fehler sehen wir bei Anfängern immer wieder - alle drei sind leicht zu vermeiden, wenn du sie einmal kennst.
Fehler 1: Dequeue oder Pop auf eine leere Collection
Der Klassiker: Du rufst `Dequeue()` oder `Pop()` auf, obwohl die Collection leer ist. Das Ergebnis ist eine `InvalidOperationException`. Und Vorsicht: Auch `Peek()` auf einer leeren Collection wirft diese Exception. Immer vorher prüfen:
// Falsch: crasht bei leerer Queue
string ticket = tickets.Dequeue();
// Richtig: erst pruefen, dann entnehmen
if (tickets.Count > 0)
{
string ticket = tickets.Dequeue();
}Wie du solche Exceptions sauber behandelst, zeigen wir in C# Exception Handling.
Fehler 2: Elemente während foreach entfernen
Eine `foreach`-Schleife über eine Queue oder einen Stack darf diese nicht verändern. Wer innerhalb der Schleife `Dequeue()` oder `Pop()` aufruft, bekommt eine `InvalidOperationException` geworfen:
// Falsch: Exception zur Laufzeit
foreach (string t in tickets)
{
tickets.Dequeue(); // crasht!
}
// Richtig: mit while und Count arbeiten
while (tickets.Count > 0)
{
string t = tickets.Dequeue();
}Warum? Weil der Enumerator der Collection über ihren aktuellen Zustand wacht - sobald sich die Datenstruktur ändert, gilt sie als ungültig. Mehr dazu in IEnumerable und foreach in C#.
Fehler 3: Die falsche Datenstruktur wählen
Eine `List<T>` kann alles, was Queue und Stack auch können - technisch gesehen. Aber sie verschleiert deine Absicht. Wenn dein Code `queue[5]` erlaubt, obwohl semantisch nur „vorne entnehmen" erlaubt sein soll, entsteht ein Bug-Risiko. Die Wahl der passenden Datenstruktur dokumentiert dein Design. Wer `Queue<T>` sieht, weiß sofort: Hier geht es um Reihenfolge beim Hinein- und Herausholen.
Merke: Wähle die Datenstruktur nach der Bedeutung aus, nicht nach dem, was gerade funktioniert. Queue = Reihenfolge, Stack = Umkehrung.
Übungstipp: Bau eine Undo-Funktion
Nimm einen einfachen Konsolen-Editor: Der Nutzer gibt Textzeilen ein, mit dem Befehl `undo` wird die letzte Zeile gelöscht, mit `print` wird alles ausgegeben. Speichere die Zeilen in einem `Stack<string>`, pushe jede neue Zeile und pope bei `undo`. Das schaffst du in unter 30 Minuten - und du hast LIFO nicht nur gelesen, sondern gelebt. Danach erweiterst du das Ganze um eine `Queue<string>` für einen Befehlsverlauf.
FAQ: Häufige Fragen zu Queue und Stack in C#
Was ist der Unterschied zwischen Queue und Stack in C#?
Eine Queue arbeitet nach FIFO (First In, First Out) - das erste Element kommt zuerst heraus. Ein Stack arbeitet nach LIFO (Last In, First Out) - das letzte Element kommt zuerst heraus.
Wann nutze ich eine Queue, wann einen Stack?
Queue, wenn die Reihenfolge des Eintreffens zählt (Tickets, Druckaufträge, Nachrichtenwarteschlangen). Stack, wenn es auf das zuletzt Geschehene ankommt (Undo, Back-Navigation, Klammern prüfen beim Parser).
Was passiert bei Dequeue() oder Pop() auf einer leeren Collection?
Es wird eine `InvalidOperationException` geworfen. Prüfe vorher mit `Count > 0` oder fange die Exception ab. Dasselbe gilt übrigens für `Peek()`.
Was macht Peek() bei Queue und Stack?
`Peek()` gibt das nächste Element zurück (bei der Queue das vorderste, beim Stack das oberste), ohne es zu entfernen. Die Collection bleibt unverändert.
Sind Queue und Stack threadsicher?
Nein, `Queue<T>` und `Stack<T>` aus `System.Collections.Generic` sind nicht threadsicher. Für parallele Producer-Consumer-Szenarien nutzt du stattdessen `System.Collections.Concurrent.ConcurrentQueue<T>`. Mehr zu Nebenläufigkeit in C# async await Task.
Fazit
Queue und Stack gehören in C# zu den einfachsten und gleichzeitig nützlichsten Datenstrukturen. Die Essenz: Queue = FIFO für Reihenfolge, Stack = LIFO für Umkehrung. Mit `Enqueue`/`Dequeue` bzw. `Push`/`Pop` bedienst du beide intuitiv - achte nur auf die leere Collection und verändere nichts während `foreach`. Diese Themen kommen übrigens regelmäßig in IHK-Prüfungen und Universitätsvorlesungen zu Algorithmen und Datenstrukturen vor.
Wenn du bei C#-Grundlagen, Prüfungsvorbereitung oder deinen ersten Berufsjahren Unterstützung brauchst: Bei study-it.education findest du individuelle Nachhilfe genau für Azubis, Studenten und Quereinsteiger - mit Erklärungen auf deinem Level.
Want 1:1 help with this topic?
Need someone to walk through this with you?
Instead of re-reading: 30 min with a senior dev.
Book a free first chat →
Queue (FIFO) und Stack (LIFO) in C# erklärt: Methoden, Unterschiede und praktische Beispiele für Azubis, Studenten und Berufseinsteiger.
marcel.schmidtpeter@study-it.education →More reading
C# JSON mit System.Text.Json lesen & schreiben – einfach erklärt
JSON-Daten in C# lesen und schreiben? Mit System.Text.Json gelingt dir Serialisierung & Deserialisierung – einfach erklärt für alle IT-Einsteiger.
C# xUnit Unit Test: So schreibst du deine ersten Unit Tests
Unit Tests mit xUnit machen deinen C#-Code belastbar. In diesem Tutorial lernst du [Fact], [Theory] und Assert kennen – für Einsteiger erklärt.
C# Datenbank verbinden: ADO.NET & Entity Framework einfach erklärt
So greifst du aus C# auf Datenbanken zu: mit ADO.NET für direktes SQL oder EF Core als modernem ORM – beide Wege mit Beispielen erklärt.