diff --git a/DIRECTORY.md b/DIRECTORY.md index 0ed6b7c5b..7f073a5ad 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -57,7 +57,8 @@ * [Linkedlist Implentation Usingarray](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/linkedlist_implentation_usingarray.cpp) * [List Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/list_array.cpp) * [Morrisinorder](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/morrisinorder.cpp) - * [Queue](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/queue.h) + * [Node](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/node.hpp) + * [Queue](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/queue.hpp) * [Queue Using Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/queue_using_array.cpp) * [Queue Using Array2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/queue_using_array2.cpp) * [Queue Using Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/queue_using_linked_list.cpp) diff --git a/data_structures/node.hpp b/data_structures/node.hpp new file mode 100644 index 000000000..ff920299b --- /dev/null +++ b/data_structures/node.hpp @@ -0,0 +1,46 @@ +/** + * @file + * @brief Provides Node class and related utilities + **/ +#ifndef DATA_STRUCTURES_NODE_HPP_ +#define DATA_STRUCTURES_NODE_HPP_ + +#include /// for std::cout +#include /// for std::shared_ptr +#include /// for std::vector + +/** Definition of the node as a linked-list + * \tparam ValueType type of data nodes of the linked list should contain + */ +template +struct Node { + using value_type = ValueType; + ValueType data = {}; + std::shared_ptr> next = {}; +}; + +template +void traverse(const Node* const inNode, const Action& action) { + if (inNode) { + action(*inNode); + traverse(inNode->next.get(), action); + } +} + +template +void display_all(const Node* const inNode) { + traverse(inNode, + [](const Node& curNode) { std::cout << curNode.data << " "; }); +} + +template +std::vector push_all_to_vector( + const Node* const inNode, const std::size_t expected_size = 0) { + std::vector res; + res.reserve(expected_size); + traverse(inNode, + [&res](const Node& curNode) { res.push_back(curNode.data); }); + return res; +} + +#endif // DATA_STRUCTURES_NODE_HPP_ diff --git a/data_structures/queue.h b/data_structures/queue.h deleted file mode 100644 index 3cb551741..000000000 --- a/data_structures/queue.h +++ /dev/null @@ -1,88 +0,0 @@ -/* This class specifies the basic operation on a queue as a linked list */ -#ifndef DATA_STRUCTURES_QUEUE_H_ -#define DATA_STRUCTURES_QUEUE_H_ - -#include -#include - -/** Definition of the node */ -template -struct node { - Kind data; - node *next; -}; - -/** Definition of the queue class */ -template -class queue { - public: - /** Show queue */ - void display() { - node *current = queueFront; - std::cout << "Front --> "; - while (current != NULL) { - std::cout << current->data << " "; - current = current->next; - } - std::cout << std::endl; - std::cout << "Size of queue: " << size << std::endl; - } - - /** Default constructor*/ - queue() { - queueFront = NULL; - queueRear = NULL; - size = 0; - } - - /** Destructor */ - ~queue() {} - - /** Determine whether the queue is empty */ - bool isEmptyQueue() { return (queueFront == NULL); } - - /** Add new item to the queue */ - void enQueue(Kind item) { - node *newNode; - newNode = new node; - newNode->data = item; - newNode->next = NULL; - if (queueFront == NULL) { - queueFront = newNode; - queueRear = newNode; - } else { - queueRear->next = newNode; - queueRear = queueRear->next; - } - size++; - } - - /** Return the first element of the queue */ - Kind front() { - assert(queueFront != NULL); - return queueFront->data; - } - - /** Remove the top element of the queue */ - void deQueue() { - node *temp; - if (!isEmptyQueue()) { - temp = queueFront; - queueFront = queueFront->next; - delete temp; - size--; - } else { - std::cout << "Queue is empty !" << std::endl; - } - } - - /** Clear queue */ - void clear() { queueFront = NULL; } - - private: - node *queueFront; /**< Pointer to the front of the queue */ - node *queueRear; /**< Pointer to the rear of the queue */ - int size; -}; - -#endif // DATA_STRUCTURES_QUEUE_H_ diff --git a/data_structures/queue.hpp b/data_structures/queue.hpp new file mode 100644 index 000000000..cd358a6ef --- /dev/null +++ b/data_structures/queue.hpp @@ -0,0 +1,104 @@ +/* This class specifies the basic operation on a queue as a linked list */ +#ifndef DATA_STRUCTURES_QUEUE_HPP_ +#define DATA_STRUCTURES_QUEUE_HPP_ + +#include "node.hpp" + +/** Definition of the queue class */ +template +class queue { + using node_type = Node; + + public: + using value_type = ValueType; + /** + * @brief prints the queue into the std::cout + */ + void display() const { + std::cout << "Front --> "; + display_all(this->queueFront.get()); + std::cout << '\n'; + std::cout << "Size of queue: " << size << '\n'; + } + + /** + * @brief converts the queue into the std::vector + * @return std::vector containning all of the elements of the queue in the + * same order + */ + std::vector toVector() const { + return push_all_to_vector(this->queueFront.get(), this->size); + } + + private: + /** + * @brief throws an exception if queue is empty + * @exception std::invalid_argument if queue is empty + */ + void ensureNotEmpty() const { + if (isEmptyQueue()) { + throw std::invalid_argument("Queue is empty."); + } + } + + public: + /** + * @brief checks if the queue has no elements + * @return true if the queue is empty, false otherwise + */ + bool isEmptyQueue() const { return (queueFront == nullptr); } + + /** + * @brief inserts a new item into the queue + */ + void enQueue(const value_type& item) { + auto newNode = std::make_shared(); + newNode->data = item; + newNode->next = nullptr; + if (isEmptyQueue()) { + queueFront = newNode; + queueRear = newNode; + } else { + queueRear->next = newNode; + queueRear = queueRear->next; + } + ++size; + } + + /** + * @return the first element of the queue + * @exception std::invalid_argument if queue is empty + */ + value_type front() const { + ensureNotEmpty(); + return queueFront->data; + } + + /** + * @brief removes the first element from the queue + * @exception std::invalid_argument if queue is empty + */ + void deQueue() { + ensureNotEmpty(); + queueFront = queueFront->next; + --size; + } + + /** + * @brief removes all elements from the queue + */ + void clear() { + queueFront = nullptr; + queueRear = nullptr; + size = 0; + } + + private: + std::shared_ptr queueFront = + {}; /**< Pointer to the front of the queue */ + std::shared_ptr queueRear = + {}; /**< Pointer to the rear of the queue */ + std::size_t size = 0; +}; + +#endif // DATA_STRUCTURES_QUEUE_HPP_ diff --git a/data_structures/stack.hpp b/data_structures/stack.hpp index 419a07c67..84336453a 100644 --- a/data_structures/stack.hpp +++ b/data_structures/stack.hpp @@ -7,28 +7,9 @@ #ifndef DATA_STRUCTURES_STACK_HPP_ #define DATA_STRUCTURES_STACK_HPP_ -#include /// for IO operations -#include /// for std::shared_ptr #include /// for std::invalid_argument -#include /// for std::vector -/** Definition of the node as a linked-list - * \tparam ValueType type of data nodes of the linked list should contain - */ -template -struct node { - ValueType data = {}; ///< data at current node - std::shared_ptr> next = - {}; ///< pointer to the next ::node instance -}; - -template -void traverse(const Node* const inNode, const Action& action) { - if (inNode) { - action(*inNode); - traverse(inNode->next.get(), action); - } -} +#include "node.hpp" /// for Node /** Definition of the stack class * \tparam value_type type of data nodes of the linked list in the stack should @@ -42,20 +23,13 @@ class stack { /** Show stack */ void display() const { std::cout << "Top --> "; - traverse(stackTop.get(), [](const node& inNode) { - std::cout << inNode.data << " "; - }); - std::cout << std::endl; + display_all(this->stackTop.get()); + std::cout << '\n'; std::cout << "Size of stack: " << size << std::endl; } std::vector toVector() const { - std::vector res; - res.reserve(this->size); - traverse(stackTop.get(), [&res](const node& inNode) { - res.push_back(inNode.data); - }); - return res; + return push_all_to_vector(this->stackTop.get(), this->size); } private: @@ -71,7 +45,7 @@ class stack { /** Add new item to the stack */ void push(const value_type& item) { - auto newNode = std::make_shared>(); + auto newNode = std::make_shared>(); newNode->data = item; newNode->next = stackTop; stackTop = newNode; @@ -98,7 +72,7 @@ class stack { } private: - std::shared_ptr> stackTop = + std::shared_ptr> stackTop = {}; /**< Pointer to the stack */ std::size_t size = 0; ///< size of stack }; diff --git a/data_structures/test_queue.cpp b/data_structures/test_queue.cpp index 387ccf2f7..d0fa3502e 100644 --- a/data_structures/test_queue.cpp +++ b/data_structures/test_queue.cpp @@ -1,41 +1,93 @@ -#include -#include +#include /// for assert +#include /// for std::cout -#include "./queue.h" +#include "./queue.hpp" + +template +void testConstructedQueueIsEmpty() { + const queue curQueue; + assert(curQueue.isEmptyQueue()); +} + +void testEnQueue() { + queue curQueue; + curQueue.enQueue(10); + assert(curQueue.toVector() == std::vector({10})); + curQueue.enQueue(20); + assert(curQueue.toVector() == std::vector({10, 20})); + curQueue.enQueue(30); + curQueue.enQueue(40); + assert(curQueue.toVector() == std::vector({10, 20, 30, 40})); +} + +void testDeQueue() { + queue curQueue; + curQueue.enQueue(10); + curQueue.enQueue(20); + curQueue.enQueue(30); + + curQueue.deQueue(); + assert(curQueue.toVector() == std::vector({20, 30})); + + curQueue.deQueue(); + assert(curQueue.toVector() == std::vector({30})); + + curQueue.deQueue(); + assert(curQueue.isEmptyQueue()); +} + +void testFront() { + queue curQueue; + curQueue.enQueue(10); + assert(curQueue.front() == 10); + curQueue.enQueue(20); + assert(curQueue.front() == 10); +} + +void testQueueAfterClearIsEmpty() { + queue curQueue; + curQueue.enQueue(10); + curQueue.enQueue(20); + curQueue.enQueue(30); + curQueue.clear(); + assert(curQueue.isEmptyQueue()); +} + +void testFrontThrowsAnInvalidArgumentWhenQueueEmpty() { + const queue curQueue; + bool wasException = false; + try { + curQueue.front(); + } catch (const std::invalid_argument&) { + wasException = true; + } + assert(wasException); +} + +void testDeQueueThrowsAnInvalidArgumentWhenQueueEmpty() { + queue curQueue; + bool wasException = false; + try { + curQueue.deQueue(); + } catch (const std::invalid_argument&) { + wasException = true; + } + assert(wasException); +} int main() { - queue q; - std::cout << "---------------------- Test construct ----------------------" - << std::endl; - q.display(); - std::cout - << "---------------------- Test isEmptyQueue ----------------------" - << std::endl; - if (q.isEmptyQueue()) - std::cout << "PASS" << std::endl; - else - std::cout << "FAIL" << std::endl; - std::cout << "---------------------- Test enQueue ----------------------" - << std::endl; - std::cout << "After Hai, Jeff, Tom, Jkingston go into queue: " << std::endl; - q.enQueue("Hai"); - q.enQueue("Jeff"); - q.enQueue("Tom"); - q.enQueue("Jkingston"); - q.display(); - std::cout << "---------------------- Test front ----------------------" - << std::endl; - std::string value = q.front(); - if (value == "Hai") - std::cout << "PASS" << std::endl; - else - std::cout << "FAIL" << std::endl; - std::cout << "---------------------- Test deQueue ----------------------" - << std::endl; - q.display(); - q.deQueue(); - q.deQueue(); - std::cout << "After Hai, Jeff left the queue: " << std::endl; - q.display(); + testConstructedQueueIsEmpty(); + testConstructedQueueIsEmpty(); + testConstructedQueueIsEmpty>(); + + testEnQueue(); + testDeQueue(); + + testQueueAfterClearIsEmpty(); + + testFrontThrowsAnInvalidArgumentWhenQueueEmpty(); + testDeQueueThrowsAnInvalidArgumentWhenQueueEmpty(); + + std::cout << "All tests pass!\n"; return 0; } diff --git a/data_structures/test_stack.cpp b/data_structures/test_stack.cpp index dfff0b50e..81039e796 100644 --- a/data_structures/test_stack.cpp +++ b/data_structures/test_stack.cpp @@ -157,7 +157,7 @@ void testAssign() { assert(stackB.toVector() == otherExpectedDataB); } -void testTopThrowsAnvalidArgumentWhenStackEmpty() { +void testTopThrowsAnInvalidArgumentWhenStackEmpty() { const stack curStack; bool wasException = false; try { @@ -168,7 +168,7 @@ void testTopThrowsAnvalidArgumentWhenStackEmpty() { assert(wasException); } -void testPopThrowsAnvalidArgumentWhenStackEmpty() { +void testPopThrowsAnInvalidArgumentWhenStackEmpty() { stack curStack; bool wasException = false; try { @@ -195,8 +195,8 @@ int main() { testAssign(); - testTopThrowsAnvalidArgumentWhenStackEmpty(); - testPopThrowsAnvalidArgumentWhenStackEmpty(); + testTopThrowsAnInvalidArgumentWhenStackEmpty(); + testPopThrowsAnInvalidArgumentWhenStackEmpty(); std::cout << "All tests pass!\n"; return 0;