From ca157d75628f68ab01d589267f26d17751a87e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=C3=A9sio=20Junior?= Date: Fri, 5 Oct 2018 11:56:57 -0300 Subject: [PATCH] Implement Standard and Circular Queue (C++) (#116) --- .../Queue/C++/CircularQueue/CircularQueue.cpp | 89 +++++++++++ .../Queue/C++/CircularQueue/CircularQueue.hpp | 29 ++++ .../CircularQueue/CircularQueueIntImpl.cpp | 3 + .../Queue/C++/StandardQueue/SimpleQueue.cpp | 97 +++++++++++ .../Queue/C++/StandardQueue/SimpleQueue.hpp | 30 ++++ .../C++/StandardQueue/SimpleQueueIntImpl.cpp | 3 + Data Structures/Queue/C++/Test/Makefile | 19 +++ Data Structures/Queue/C++/Test/test.cpp | 150 ++++++++++++++++++ .../Queue/C++/resources/Exceptions.hpp | 14 ++ Data Structures/Queue/C++/resources/Queue.hpp | 25 +++ 10 files changed, 459 insertions(+) create mode 100644 Data Structures/Queue/C++/CircularQueue/CircularQueue.cpp create mode 100644 Data Structures/Queue/C++/CircularQueue/CircularQueue.hpp create mode 100644 Data Structures/Queue/C++/CircularQueue/CircularQueueIntImpl.cpp create mode 100644 Data Structures/Queue/C++/StandardQueue/SimpleQueue.cpp create mode 100644 Data Structures/Queue/C++/StandardQueue/SimpleQueue.hpp create mode 100644 Data Structures/Queue/C++/StandardQueue/SimpleQueueIntImpl.cpp create mode 100644 Data Structures/Queue/C++/Test/Makefile create mode 100644 Data Structures/Queue/C++/Test/test.cpp create mode 100644 Data Structures/Queue/C++/resources/Exceptions.hpp create mode 100644 Data Structures/Queue/C++/resources/Queue.hpp diff --git a/Data Structures/Queue/C++/CircularQueue/CircularQueue.cpp b/Data Structures/Queue/C++/CircularQueue/CircularQueue.cpp new file mode 100644 index 00000000..a7778f08 --- /dev/null +++ b/Data Structures/Queue/C++/CircularQueue/CircularQueue.cpp @@ -0,0 +1,89 @@ +#include "CircularQueue.hpp" + +/* +* SimpleQueue class constructor +* @params length of the queue +*/ +template +CircularQueue::CircularQueue(int size){ + this->head_ptr = (T*) calloc(size,sizeof(T)); + this->head_index = -1; + this->tail = -1; + this->elements = 0; + this->size = size; +} + + +/* +* Insert a new element in tail of the queue or throw an exception if queue is full. +* Complexity : O(1) +* @param element +* @throw QueueOverflowException +*/ +template +void CircularQueue::enqueue(T element){ + if(this->isFull()){ + throw this->overflow; + } + this->elements++; + if(this->head_index == -1 && this->tail == -1){ + this->head_index = (this->head_index + 1 ) % this->size; + } + this->tail = (this->tail + 1 ) % this->size; + this->head_ptr[this->tail] = element; +} + +/* + +* Remove head element of the queue or throw an exception if queue is empty +* Complexity : O(1) +* @return element +* @throw QueueUnderflowException +*/ +template +T* CircularQueue::dequeue(){ + if(this->isEmpty()){ + throw this->underflow; + } + this->elements--; + T* aux = &this->head_ptr[this->head_index]; + this->head_index = (this->head_index + 1) % size; + return aux; +} + + +/* +* Return element in the head of the queue without remove, or NULL if queue is empty. +* Complexity: O(1) +* @return element +*/ +template +T* CircularQueue::head(){ + if(this->isEmpty()){ + return NULL; + }else{ + return &this->head_ptr[this->head_index]; + } +} + + +/* +* Return true if queue is empty or false,otherwise. +* Complexity : O(1) +* @return bool +*/ +template +bool CircularQueue::isEmpty(){ + return this->elements == 0; +} + + +/* +* Return true if queue is full or false,otherwise. +* Complexity : O(1) +* @return bool +*/ +template +bool CircularQueue::isFull(){ + return this->elements == this->size; +} diff --git a/Data Structures/Queue/C++/CircularQueue/CircularQueue.hpp b/Data Structures/Queue/C++/CircularQueue/CircularQueue.hpp new file mode 100644 index 00000000..a0237b7d --- /dev/null +++ b/Data Structures/Queue/C++/CircularQueue/CircularQueue.hpp @@ -0,0 +1,29 @@ +#ifndef _CIRCULARQUEUE_H_ +#define _CIRCULARQUEUE_H_ +/* +*@author Ionésio Junior +*/ + +#include "resources/Queue.hpp" + +/* +* Queue in circular implementation +*/ +template +class CircularQueue : public Queue{ + private: + T *head_ptr; + int tail; + int head_index; + int size; + int elements; + public: + CircularQueue(int size); + bool isEmpty() override; + bool isFull() override; + void enqueue(T element) override; + T* dequeue() override; + T* head() override; +}; + +#endif diff --git a/Data Structures/Queue/C++/CircularQueue/CircularQueueIntImpl.cpp b/Data Structures/Queue/C++/CircularQueue/CircularQueueIntImpl.cpp new file mode 100644 index 00000000..97ffb6d4 --- /dev/null +++ b/Data Structures/Queue/C++/CircularQueue/CircularQueueIntImpl.cpp @@ -0,0 +1,3 @@ +#include "CircularQueue.cpp" + +template class CircularQueue; diff --git a/Data Structures/Queue/C++/StandardQueue/SimpleQueue.cpp b/Data Structures/Queue/C++/StandardQueue/SimpleQueue.cpp new file mode 100644 index 00000000..e9c801a9 --- /dev/null +++ b/Data Structures/Queue/C++/StandardQueue/SimpleQueue.cpp @@ -0,0 +1,97 @@ +#include "SimpleQueue.hpp" + +/* +* SimpleQueue class constructor +* @params length of the queue +*/ +template +SimpleQueue::SimpleQueue(int size){ + this->head_ptr = (T*) calloc(size,sizeof(T)); + this->tail = this->head_ptr - 1; + this->size = size; +} + + +/* +* Return true if queue is empty or false,otherwise. +* Complexity : O(1) +* @return bool +*/ +template +bool SimpleQueue::isEmpty(){ + return (this->tail < this->head_ptr); +} + + +/* +* Return true if queue is full or false,otherwise. +* Complexity : O(1) +* @return bool +*/ +template +bool SimpleQueue::isFull(){ + return (this->tail == (this->head_ptr + this->size - 1)); +} + + +/* +* Insert a new element in tail of the queue or throw an exception if queue is full. +* Complexity : O(1) +* @param element +* @throw QueueOverflowException +*/ +template +void SimpleQueue::enqueue(T element){ + if(!this->isFull()){ + this->tail++; + *this->tail = element; + }else{ + throw this->overflow; + } +} + + +/* +* Remove head element of the queue or throw an exception if queue is empty +* Complexity : O(n) +* @return element +* @throw QueueUnderflowException +*/ +template +T* SimpleQueue::dequeue(){ + if(!this->isEmpty()){ + T removedElement = *(this->head_ptr); + this->shiftLeft(); + this->tail--; + this->tail[1] = removedElement; + return &this->tail[1]; + }else{ + throw this->underflow; + } +} + + +/* +* When an element is removed, this method move each element to the previous position. +*/ +template +void SimpleQueue::shiftLeft(){ + for(int *i = this->head_ptr; i < this->tail;i++){ + *i = *(i + 1); + } +} + + +/* +* Return element in the head of the queue without remove, or NULL if queue is empty. +* Complexity : O(1) +* @return element +*/ +template +T* SimpleQueue::head(){ + if(!this->isEmpty()){ + return this->head_ptr; + }else{ + return NULL; + } +} diff --git a/Data Structures/Queue/C++/StandardQueue/SimpleQueue.hpp b/Data Structures/Queue/C++/StandardQueue/SimpleQueue.hpp new file mode 100644 index 00000000..a37d3142 --- /dev/null +++ b/Data Structures/Queue/C++/StandardQueue/SimpleQueue.hpp @@ -0,0 +1,30 @@ +#ifndef _SIMPLEQUEUE_H_ +#define _SIMPLEQUEUE_H_ + +/* +*@author Ionésio Junior +*/ +#include "resources/Queue.hpp" + +//Queue.hpp +/* +* Simple Queue Implementation +*/ + +template +class SimpleQueue : public Queue{ + private: + T *head_ptr; + T *tail; + int size; + void shiftLeft(); + public: + SimpleQueue(int size); + bool isEmpty() override; + bool isFull() override; + void enqueue(T element) override; + T* dequeue() override; + T* head() override; +}; + +#endif diff --git a/Data Structures/Queue/C++/StandardQueue/SimpleQueueIntImpl.cpp b/Data Structures/Queue/C++/StandardQueue/SimpleQueueIntImpl.cpp new file mode 100644 index 00000000..40d9df6c --- /dev/null +++ b/Data Structures/Queue/C++/StandardQueue/SimpleQueueIntImpl.cpp @@ -0,0 +1,3 @@ +#include "SimpleQueue.cpp" + +template class SimpleQueue; diff --git a/Data Structures/Queue/C++/Test/Makefile b/Data Structures/Queue/C++/Test/Makefile new file mode 100644 index 00000000..b8339b57 --- /dev/null +++ b/Data Structures/Queue/C++/Test/Makefile @@ -0,0 +1,19 @@ +LIB = -L/usr/lib/x86_64-linux-gnu/ +LIBS = -lboost_unit_test_framework +INCLUDE = -I../. + +all: Test + +../StandardQueue/SimpleQueue.o: ../StandardQueue/SimpleQueueIntImpl.cpp ../StandardQueue/SimpleQueue.hpp ../StandardQueue/SimpleQueue.cpp + g++ -c $< -o $@ $(INCLUDE) + +../CircularQueue/CircularQueue.o: ../CircularQueue/CircularQueueIntImpl.cpp ../CircularQueue/CircularQueue.cpp ../CircularQueue/CircularQueue.hpp + g++ -c $< -o $@ $(INCLUDE) + +Test: ../CircularQueue/CircularQueue.o ../StandardQueue/SimpleQueue.o + g++ $^ test.cpp -o test $(LIB) $(LIBS) $(INCLUDE) -std=c++14 + +clean: + rm ../StandardQueue/SimpleQueue.o + rm ../CircularQueue/CircularQueue.o + rm test diff --git a/Data Structures/Queue/C++/Test/test.cpp b/Data Structures/Queue/C++/Test/test.cpp new file mode 100644 index 00000000..7e12005b --- /dev/null +++ b/Data Structures/Queue/C++/Test/test.cpp @@ -0,0 +1,150 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE QueueTest + +#include +#include "CircularQueue/CircularQueue.hpp" +#include "StandardQueue/SimpleQueue.hpp" +#include + +struct QueueInit{ + Queue *queue1 = new CircularQueue(10); + Queue *queue2 = new SimpleQueue(10); +}; + +BOOST_FIXTURE_TEST_SUITE(QueueTest,QueueInit) + +BOOST_AUTO_TEST_CASE(testInit){ + BOOST_CHECK(true == queue1->isEmpty()); + BOOST_CHECK(false == queue1->isFull()); + BOOST_CHECK(NULL == queue1->head()); + BOOST_CHECK(true == queue2->isEmpty()); + BOOST_CHECK(false == queue2->isFull()); + BOOST_CHECK(NULL == queue2->head()); +} + +BOOST_AUTO_TEST_CASE(testIsEmpty){ + BOOST_CHECK(true == queue1->isEmpty()); + BOOST_CHECK(true == queue2->isEmpty()); + queue1->enqueue(5); + queue2->enqueue(5); + + BOOST_CHECK(false == queue1->isEmpty()); + BOOST_CHECK(false == queue2->isEmpty()); + queue1->head(); + queue2->head(); + BOOST_CHECK(false == queue1->isEmpty()); + BOOST_CHECK(false == queue2->isEmpty()); + + + queue1->dequeue(); + queue2->dequeue(); + BOOST_CHECK(true == queue1->isEmpty()); + BOOST_CHECK(true == queue2->isEmpty()); +} + +BOOST_AUTO_TEST_CASE(testIsFull){ + BOOST_CHECK(false == queue1->isFull()); + BOOST_CHECK(false == queue2->isFull()); + + for(int i = 0 ; i < 9;i++){ + queue1->enqueue(i); + queue2->enqueue(i); + } + + BOOST_CHECK(false == queue1->isFull()); + BOOST_CHECK(false == queue2->isFull()); + + queue1->enqueue(20); + queue2->enqueue(20); + BOOST_CHECK(true == queue1->isFull()); + BOOST_CHECK(true == queue2->isFull()); +} + +BOOST_AUTO_TEST_CASE(testEnqueue){ + BOOST_CHECK(true == queue1->isEmpty()); + BOOST_CHECK(true == queue2->isEmpty()); + queue1->enqueue(0); + queue2->enqueue(4); + BOOST_CHECK(false == queue1->isEmpty()); + BOOST_CHECK(false == queue2->isEmpty()); + BOOST_CHECK(false == queue1->isFull()); + BOOST_CHECK(false == queue2->isFull()); + BOOST_CHECK(0 == *(queue1->head())); + + for(int i = 1 ; i < 10;i++){ + queue1->enqueue(i); + queue2->enqueue(i); + BOOST_CHECK(0 == *(queue1->head())); + BOOST_CHECK(4 == *(queue2->head())); + } + BOOST_CHECK(true == queue1->isFull()); + BOOST_CHECK(true == queue2->isFull()); +} + +BOOST_AUTO_TEST_CASE(testDequeue){ + BOOST_CHECK(true == queue1->isEmpty()); + BOOST_CHECK(true == queue2->isEmpty()); + + for(int i = 0 ; i < 10;i++){ + queue1->enqueue(i); + queue2->enqueue(i); + } + + BOOST_CHECK(false == queue1->isEmpty()); + BOOST_CHECK(false == queue2->isEmpty()); + BOOST_CHECK(true == queue1->isFull()); + BOOST_CHECK(true == queue2->isFull()); + + for(int i = 0 ; i < 10;i++){ + BOOST_CHECK(i == *(queue1->dequeue())); + BOOST_CHECK(i == *(queue2->dequeue())); + } + + BOOST_CHECK(true == queue1->isEmpty()); + BOOST_CHECK(true == queue2->isEmpty()); + BOOST_CHECK(false == queue1->isFull()); + BOOST_CHECK(false == queue2->isFull()); + +} + +BOOST_AUTO_TEST_CASE(testHead){ + BOOST_CHECK(true == queue1->isEmpty()); + BOOST_CHECK(true == queue2->isEmpty()); + BOOST_CHECK(NULL == queue1->head()); + BOOST_CHECK(NULL == queue2->head()); + + for(int i = 0 ; i < 10;i++){ + queue1->enqueue(i); + queue2->enqueue(i); + BOOST_CHECK(0 == *(queue1->head())); + BOOST_CHECK(0 == *(queue2->head())); + } + BOOST_CHECK(true == queue1->isFull()); + BOOST_CHECK(true == queue2->isFull()); + BOOST_CHECK(false == queue1->isEmpty()); + BOOST_CHECK(false == queue2->isEmpty()); + + for(int i = 0; i < 10;i++){ + BOOST_CHECK(i == *(queue1->head())); + BOOST_CHECK(i == *(queue2->head())); + BOOST_CHECK(queue1->head() == queue1->dequeue()); + queue2->dequeue(); + } + BOOST_CHECK(false == queue1->isFull()); + BOOST_CHECK(false == queue2->isFull()); + BOOST_CHECK(true == queue1->isEmpty()); + BOOST_CHECK(true == queue2->isEmpty()); +} + +BOOST_AUTO_TEST_CASE(testException){ + BOOST_CHECK_THROW(queue1->dequeue(),QueueUnderflowException); + BOOST_CHECK_THROW(queue2->dequeue(),QueueUnderflowException); + for(int i = 0; i < 10;i++){ + queue1->enqueue(i); + queue2->enqueue(i); + } + BOOST_CHECK_THROW(queue1->enqueue(10),QueueOverflowException); + BOOST_CHECK_THROW(queue2->enqueue(10),QueueOverflowException); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/Data Structures/Queue/C++/resources/Exceptions.hpp b/Data Structures/Queue/C++/resources/Exceptions.hpp new file mode 100644 index 00000000..8e268d6b --- /dev/null +++ b/Data Structures/Queue/C++/resources/Exceptions.hpp @@ -0,0 +1,14 @@ +#include +#include + +class QueueUnderflowException : public std::exception{ + virtual const char* what() const throw(){ + return "Queue is Empty!!"; + } +}; + +class QueueOverflowException : public std::exception{ + virtual const char* what() const throw(){ + return "Queue is Full!!"; + } +}; diff --git a/Data Structures/Queue/C++/resources/Queue.hpp b/Data Structures/Queue/C++/resources/Queue.hpp new file mode 100644 index 00000000..1a778691 --- /dev/null +++ b/Data Structures/Queue/C++/resources/Queue.hpp @@ -0,0 +1,25 @@ +#ifndef _QUEUE_H_ +#define _QUEUE_H_ +/* +*@author Ionésio Junior +*/ +#include +#include +#include "Exceptions.hpp" + +/* +* Queue Abstract class implementation +*/ +template +class Queue{ + public: + QueueUnderflowException underflow; + QueueOverflowException overflow; + virtual bool isEmpty() = 0; + virtual bool isFull() = 0; + virtual void enqueue(T element) = 0; + virtual T* dequeue() = 0; + virtual T* head() = 0; +}; + +#endif