Einleitung: Warum braucht man Aufgabenwarteschlangen in C++?
\nStellen Sie sich vor, Sie stehen an der Kasse im Supermarkt an. Der Erste, der kommt, wird zuerst bedient. In der Programmierung nennt man eine solche Struktur Warteschlange (queue). Es ist einer der grundlegenden Datentypen, der nach dem FIFO-Prinzip (First In, First Out) funktioniert – „Der Erste rein, der Erste raus“.
\nIn C++ werden Aufgabenwarteschlangen überall eingesetzt: von der Verarbeitung von Netzwerkanfragen bis zur Thread-Verwaltung in Multithread-Anwendungen. Für einen Programmieranfänger ist das Verständnis von Warteschlangen ein Schritt zur Beherrschung komplexerer Themen wie asynchroner Programmierung und Entwurfsmustern.
\nIn diesem Artikel werden wir uns ansehen, wie man Warteschlangen in C++ erstellt und verwendet, den Standardcontainer std::queue betrachten, einige praktische Beispiele schreiben und typische Anfängerfehler besprechen.
Grundlagen der Warteschlange: Theorie und erstes Beispiel
\nWas ist eine Warteschlange?
\nEine Warteschlange ist ein abstrakter Datentyp, der zwei grundlegende Operationen unterstützt:
\n- \n
- Hinzufügen eines Elements am Ende der Warteschlange (enqueue / push); \n
- Entfernen eines Elements vom Anfang der Warteschlange (dequeue / pop). \n
In C++ ist die Standard-Warteschlange in der Header-Datei <queue> als Klasse std::queue implementiert. Standardmäßig verwendet sie std::deque als zugrunde liegenden Container, Sie können ihn jedoch durch std::list ersetzen.
Erstes Beispiel: Warteschlange von Zahlen
\nSchreiben wir ein einfaches Programm, das eine Warteschlange von ganzen Zahlen erstellt, einige Werte hinzufügt und sie auf dem Bildschirm ausgibt.
\n#include <iostream>\n#include <queue>\n\nint main() {\n std::queue<int> my_queue;\n\n // Elemente zur Warteschlange hinzufügen\n my_queue.push(10);\n my_queue.push(20);\n my_queue.push(30);\n\n std::cout << "Erstes Element (front): " << my_queue.front() << std::endl;\n std::cout << "Letztes Element (back): " << my_queue.back() << std::endl;\n std::cout << "Größe der Warteschlange: " << my_queue.size() << std::endl;\n\n // Elemente entfernen\n while (!my_queue.empty()) {\n std::cout << "Entfernt: " << my_queue.front() << std::endl;\n my_queue.pop();\n }\n\n return 0;\n}\nErgebnis der Programmausführung:
\nErstes Element (front): 10\nLetztes Element (back): 30\nGröße der Warteschlange: 3\nEntfernt: 10\nEntfernt: 20\nEntfernt: 30\nBeachten Sie: front() gibt das erste Element zurück (das als nächstes entfernt wird), während back() das zuletzt hinzugefügte Element zurückgibt. Die Methode pop() entfernt das Element, gibt es aber nicht zurück – das ist wichtig zu merken!
Wichtige Methoden von std::queue
\nFür die effiziente Arbeit mit einer Warteschlange müssen Sie alle ihre Methoden kennen. Hier ist die vollständige Liste:
\n- \n
push(const T& value)– fügt ein Element am Ende der Warteschlange hinzu; \n pop()– entfernt das erste Element (gibt es nicht zurück); \n front()– gibt eine Referenz auf das erste Element zurück; \n back()– gibt eine Referenz auf das letzte Element zurück; \n empty()– prüft, ob die Warteschlange leer ist (gibt true/false zurück); \n size()– gibt die Anzahl der Elemente zurück. \n
Wichtig: Überprüfen Sie vor dem Aufruf von front() oder pop() immer mit empty(), ob die Warteschlange nicht leer ist. Der Versuch, auf Elemente einer leeren Warteschlange zuzugreifen, führt zu undefiniertem Verhalten (höchstwahrscheinlich zu einem Programmabsturz).
Praktisches Beispiel: Aufgabenwarteschlange
\nLassen Sie uns nun eine reale Situation simulieren. Angenommen, wir haben ein System, das Bestellungen verarbeitet. Jede Bestellung ist eine Struktur mit einer Nummer und einer Beschreibung. Wir legen die Bestellungen in die Warteschlange