====== Queue in C++ ====== ===== MyQueue ===== //Eine Queue ist intern eine doppelt verkettete Liste, jedes Element repräsentiert dabei eine Instanz der Klasse "MyNode" template class MyQueue { private: MyNode* head; //Der Head unserer Queue, hier beginnt sie MyNode* tail; //Der Tail unserer Queue, hier endet sie public: MyQueue(); ~MyQueue(); void push(T value); //Mit der Push-Methode wird ein Element am Ende der Queue eingefügt (enqueue) void pop(); //Mit der Pop-Methode wird ein Element am Anfang der Queue gelöscht (dequeue) MyNode* getHead(); //Mit dieser Methode bekommt man den Head geliefert MyNode* getTail(); //Mit dieser Methode bekommt man den Tail geliefert bool isEmpty(); //Diese Methode checkt, ob unsere Queue leer ist und liefert dann einen Boolean Wert zurück void deleteList(); //Diese Methode löscht unsere ganze Queue template friend ostream& operator << (ostream& os, const MyQueue& queue); }; template MyQueue::MyQueue() //Im Konstruktor werden nur der Head bzw. der Tail auf NULL gesetzt { this->head = this->tail = NULL; } template MyQueue::~MyQueue() {//Im Destruktor wird einfach der Speicher den die einzelnen Elemente der Queue beanspruchen mithilfe der Methode "deleteList()" freigegeben this->deleteList(); } template void MyQueue::deleteList() {//In dieser Methode wird die Liste vom ersten bis zum letzten Element durchlaufen, dabei wird immer das erste Element gelöscht MyNode* help = this->head; while(!this->isEmpty()) //Solange "help" nicht NULL ist, können haben wir ein Element welches wir löschen können { this->pop(); } this->head = this->tail = NULL; }//Zu guter Letzt setzten wir "head" und "tail" auf NULL um problemlos mit der Queue weiterarbeiten zu können template void MyQueue::push(T value) //Dem Push wird der Wert übergeben, den das neue Queue-Element haben soll { MyNode* help = new MyNode(value); //Mit dem übergebenen Wert wird ein neues Element angelegt if(this->isEmpty()) //Hier wird überprüft, ob die Queue bereits ein Element beinhaltet this->head = help; //Wäre dies nicht der Fall, so wird der Head unserer Queue auf das neue Element gesetzt else this->tail->setNext(help); //Beinhaltet unsere Queue mind. 1 Element so wird das neue Element hinten drangehängt help->setPrev(this->tail); //Zum Schluss noch die Pointer des neuen (letzten) Elements auf das vorletzte Element zeigen lassen this->tail = help;//Das neue Element ist nun das Letzte, deshalb unseren Tail (zeigt immer auf letztes Element) auf das neue Element zeigen lassen } template void MyQueue::pop() //Das Pop enfernt das 1. Element der Queue { if(!this->isEmpty()) //Es wird überprüft ob sich ein Element in der Queue befindet { MyNode* help = this->head;//Falls wir ein Element haben, setzten wir unseren Hilfszeiger help auf dieses und unseren "head" auf das Nächste this->head = this->head->getNext(); //Wenn kein Element mehr da ist, wird "head" AUTOMATISCH auf NULL gesetzt if(this->head != NULL) this->head->setPrev(NULL); //Der Zeiger zum vorderen Element wird gekappt else this->tail = NULL; //Wenn "head" NULL ist, wird "tail" auch auf NULL gesetzt help->setNext(NULL); //Nur noch "help" zeigt auf das zu löschende Element" delete help; //Der Speicher den das Element beansprucht wird freigegeben } } template MyNode* MyQueue::getHead() { return this->head; //Diese Methode liefert einfach den Beginn der Queue (head) zurück } template MyNode* MyQueue::getTail() { return this->tail; //Diese Methode liefert einfach das Ende der Queue (tail) zurück } template bool MyQueue::isEmpty() //Diese Methode checkt, ob die Queue leer ist { //Ist sie leer, wird "true" zurückgeliefert, enthält sie mindestens ein Element, wird "false" geliefert bool ret = false; if(this->head == NULL && this->tail == NULL) ret = true; return ret; } template ostream& operator << (ostream& os, const MyQueue& queue) {//Mit dem überladenen Output-Operator kann man unsere Queue ganz einfach ausgegeben werden MyNode* help = queue.head; while(help != NULL) {//Wir durchlaufen einfach die Queue vom ersten bis zum letzten Element und geben dabei den Wert jedes einzelnen Elements aus cout << help->getValue() << " "; help = help->getNext(); } return os; } ===== MyNode ===== template class MyNode //Eine Node ist ein Element der Queue { private: MyNode* next; //Pointer der auf das folgende Element zeigt MyNode* prev; //Pointer der auf das vorhergehende Element zeigt T value; public: MyNode(T value); void setValue(T value); //Methode um explizit den Wert eines Elements neu zu setzten T getValue(); //Liefert den Wert des aktuellen Elements MyNode* getNext(); //Liefert das nächste Element MyNode* getPrev(); //Liefert das vorhergehende Element void setNext(MyNode* node); //Biegt den Zeiger, der auf das nächste Element zeigt, auf das übergebene Element um void setPrev(MyNode* node); //Biegt den Zeiger, der auf das vorhergehende Element zeigt, auf das übergebene Element um }; template MyNode::MyNode(T value) //Im Konstruktor wird dem Element ein Wert (value) zugewiesen, //"next" und "prev" werden dabei auf NULL gesetzt { this->next = NULL; this->prev = NULL; this->value = value; } template void MyNode::setValue(T value) { this->value = value; //Methode um den Wert des Elements neu zu setzen } template T MyNode::getValue() { return this->value; //Liefert den Wert des Elements } template MyNode* MyNode::getNext() { return this->next; //Liefert das Element auf das der "next"-Pointer verweist } template MyNode* MyNode::getPrev() { return this->prev; //Liefert das Element auf das der "prev"-Pointer verweist } template void MyNode::setNext(MyNode* node) { this->next = node; //Diese Methode setzt den "next"-Pointer auf ein neues Element } template void MyNode::setPrev(MyNode* node) { this->prev = node; //Diese Methode setzt den "prev"-Pointer auf ein neues Element }