diff --git a/data_structures/stack.hpp b/data_structures/stack.hpp index 016b9ef78..34a8036b3 100644 --- a/data_structures/stack.hpp +++ b/data_structures/stack.hpp @@ -8,87 +8,60 @@ #include #include +#include +#include /** Definition of the node as a linked-list - * \tparam Type type of data nodes of the linked list should contain + * \tparam ValueType type of data nodes of the linked list should contain */ -template +template struct node { - Type data; ///< data at current node - node *next; ///< pointer to the next ::node instance + ValueType data = {}; ///< data at current node + std::shared_ptr> next = + {}; ///< pointer to the next ::node instance }; +template +void traverse(const std::shared_ptr& inNode, const Action& action) { + if (inNode) { + action(inNode); + traverse(inNode->next, action); + } +} + /** Definition of the stack class - * \tparam Type type of data nodes of the linked list in the stack should + * \tparam value_type type of data nodes of the linked list in the stack should * contain */ -template +template class stack { public: + using value_type = ValueType; + /** Show stack */ void display() { - node *current = stackTop; std::cout << "Top --> "; - while (current != nullptr) { - std::cout << current->data << " "; - current = current->next; - } + traverse(stackTop, + [](const auto inNode) { std::cout << inNode->data << " "; }); std::cout << std::endl; std::cout << "Size of stack: " << size << std::endl; } - /** Default constructor*/ - stack() { - stackTop = nullptr; - size = 0; - } - - /** Copy constructor*/ - explicit stack(const stack &otherStack) { - node *newNode, *current, *last; - - if (otherStack.stackTop == nullptr) { - stackTop = nullptr; - } else { - current = otherStack.stackTop; - stackTop = new node; - stackTop->data = current->data; - stackTop->next = nullptr; - last = stackTop; - current = current->next; - /* Copy the remaining stack */ - while (current != nullptr) { - newNode = new node; - newNode->data = current->data; - newNode->next = nullptr; - last->next = newNode; - last = newNode; - current = current->next; - } - } - size = otherStack.size; - } - - private: - void deleteAllNodes() { - while (stackTop != nullptr) { - const auto tmpNode = stackTop; - stackTop = stackTop->next; - delete tmpNode; - } + auto toVector() const { + std::vector res; + res.reserve(this->size); + traverse(stackTop, + [&res](const auto inNode) { res.push_back(inNode->data); }); + return res; } public: - /** Destructor */ - ~stack() { deleteAllNodes(); } - /** Determine whether the stack is empty */ bool isEmptyStack() { return (stackTop == nullptr); } /** Add new item to the stack */ - void push(Type item) { - node *newNode; - newNode = new node; + void push(const value_type& item) { + auto newNode = std::make_shared>(); newNode->data = item; newNode->next = stackTop; stackTop = newNode; @@ -96,18 +69,15 @@ class stack { } /** Return the top element of the stack */ - Type top() { + value_type top() const { assert(stackTop != nullptr); return stackTop->data; } /** Remove the top element of the stack */ void pop() { - node *temp; if (!isEmptyStack()) { - temp = stackTop; stackTop = stackTop->next; - delete temp; size--; } else { std::cout << "Stack is empty !" << std::endl; @@ -116,41 +86,13 @@ class stack { /** Clear stack */ void clear() { - deleteAllNodes(); + stackTop = nullptr; size = 0; } - /** Overload "=" the assignment operator */ - stack &operator=(const stack &otherStack) { - node *newNode, *current, *last; - - deleteAllNodes(); - if (otherStack.stackTop == nullptr) { - stackTop = nullptr; - } else { - current = otherStack.stackTop; - stackTop = new node; - stackTop->data = current->data; - stackTop->next = nullptr; - last = stackTop; - current = current->next; - /* Copy the remaining stack */ - while (current != nullptr) { - newNode = new node; - newNode->data = current->data; - newNode->next = nullptr; - last->next = newNode; - last = newNode; - current = current->next; - } - } - size = otherStack.size; - return *this; - } - private: - node *stackTop; /**< Pointer to the stack */ - int size; ///< size of stack + std::shared_ptr> stackTop = {}; /**< Pointer to the stack */ + std::size_t size = 0; ///< size of stack }; #endif // DATA_STRUCTURES_STACK_HPP_ diff --git a/data_structures/test_stack.cpp b/data_structures/test_stack.cpp index 9a7cc18ff..541fe872c 100644 --- a/data_structures/test_stack.cpp +++ b/data_structures/test_stack.cpp @@ -1,61 +1,188 @@ #include +#include #include "./stack.hpp" +void assertTrue(const bool inValue) { + if (!inValue) { + std::cout << "Assertion fails!\n"; + exit(1); + } +} + +template +void assertEqual(const T& valA, const T& valB) { + assertTrue(valA == valB); +} + +template +void testConstructedStackIsEmpty() { + stack curStack; + assertTrue(curStack.isEmptyStack()); +} + +void testPush() { + using valueType = int; + stack curStack; + curStack.push(10); + curStack.push(20); + curStack.push(30); + curStack.push(40); + const auto expectedData = std::vector({40, 30, 20, 10}); + assertEqual(curStack.toVector(), expectedData); +} + +void testTop() { + using valueType = unsigned; + stack curStack; + curStack.push(1); + curStack.push(2); + curStack.push(3); + curStack.push(4); + assertEqual(curStack.top(), static_cast(4)); +} + +void testPop() { + using valueType = int; + stack curStack; + curStack.push(100); + curStack.push(200); + curStack.push(300); + + assertEqual(curStack.top(), static_cast(300)); + curStack.pop(); + assertEqual(curStack.top(), static_cast(200)); + curStack.pop(); + assertEqual(curStack.top(), static_cast(100)); + curStack.pop(); + assertTrue(curStack.isEmptyStack()); +} + +void testClear() { + stack curStack; + curStack.push(1000); + curStack.push(2000); + curStack.clear(); + assertTrue(curStack.isEmptyStack()); +} + +void testCopyOfStackHasSameData() { + stack stackA; + stackA.push(10); + stackA.push(200); + stackA.push(3000); + const auto stackB(stackA); + assertEqual(stackA.toVector(), stackB.toVector()); +} + +void testPushingToCopyDoesNotChangeOriginal() { + using valueType = int; + stack stackA; + stackA.push(10); + stackA.push(20); + stackA.push(30); + auto stackB(stackA); + stackB.push(40); + + const auto expectedDataA = std::vector({30, 20, 10}); + const auto expectedDataB = std::vector({40, 30, 20, 10}); + + assertEqual(stackA.toVector(), expectedDataA); + assertEqual(stackB.toVector(), expectedDataB); +} + +void testPoppingFromCopyDoesNotChangeOriginal() { + using valueType = int; + stack stackA; + stackA.push(10); + stackA.push(20); + stackA.push(30); + auto stackB(stackA); + stackB.pop(); + + const auto expectedDataA = std::vector({30, 20, 10}); + const auto expectedDataB = std::vector({20, 10}); + + assertEqual(stackA.toVector(), expectedDataA); + assertEqual(stackB.toVector(), expectedDataB); +} + +void testPushingToOrginalDoesNotChangeCopy() { + using valueType = int; + stack stackA; + stackA.push(10); + stackA.push(20); + stackA.push(30); + const auto stackB(stackA); + stackA.push(40); + + const auto expectedDataA = std::vector({40, 30, 20, 10}); + const auto expectedDataB = std::vector({30, 20, 10}); + + assertEqual(stackA.toVector(), expectedDataA); + assertEqual(stackB.toVector(), expectedDataB); +} + +void testPoppingFromOrginalDoesNotChangeCopy() { + using valueType = int; + stack stackA; + stackA.push(10); + stackA.push(20); + stackA.push(30); + const auto stackB(stackA); + stackA.pop(); + + const auto expectedDataA = std::vector({20, 10}); + const auto expectedDataB = std::vector({30, 20, 10}); + + assertEqual(stackA.toVector(), expectedDataA); + assertEqual(stackB.toVector(), expectedDataB); +} + +void testAssign() { + using valueType = int; + stack stackA; + stackA.push(10); + stackA.push(20); + stackA.push(30); + stack stackB = stackA; + stackA.pop(); + stackB.push(40); + + const auto expectedDataA = std::vector({20, 10}); + const auto expectedDataB = std::vector({40, 30, 20, 10}); + + assertEqual(stackA.toVector(), expectedDataA); + assertEqual(stackB.toVector(), expectedDataB); + + stackB = stackA; + stackA.pop(); + stackB.push(5); + stackB.push(6); + + const auto otherExpectedDataA = std::vector({10}); + const auto otherExpectedDataB = std::vector({6, 5, 20, 10}); + + assertEqual(stackA.toVector(), otherExpectedDataA); + assertEqual(stackB.toVector(), otherExpectedDataB); +} + int main() { - stack stk; - std::cout << "---------------------- Test construct ----------------------" - << std::endl; - stk.display(); - std::cout - << "---------------------- Test isEmptyStack ----------------------" - << std::endl; - if (stk.isEmptyStack()) { - std::cout << "PASS" << std::endl; - } else { - std::cout << "FAIL" << std::endl; - } - std::cout << "---------------------- Test push ----------------------" - << std::endl; - std::cout << "After pushing 10 20 30 40 into stack: " << std::endl; - stk.push(10); - stk.push(20); - stk.push(30); - stk.push(40); - stk.display(); - std::cout << "---------------------- Test top ----------------------" - << std::endl; - int value = stk.top(); - if (value == 40) { - std::cout << "PASS" << std::endl; - } else { - std::cout << "FAIL" << std::endl; - } - std::cout << "---------------------- Test pop ----------------------" - << std::endl; - stk.display(); - stk.pop(); - stk.pop(); - std::cout << "After popping 2 times: " << std::endl; - stk.display(); - std::cout << "---------------------- Test overload = operator " - "----------------------" - << std::endl; - stack stk1; - std::cout << "stk current: " << std::endl; - stk.display(); - std::cout << std::endl << "Assign stk1 = stk " << std::endl; - stk1 = stk; - stk1.display(); - std::cout << std::endl << "After pushing 8 9 10 into stk1:" << std::endl; - stk1.push(8); - stk1.push(9); - stk1.push(10); - stk1.display(); - std::cout << std::endl << "stk current: " << std::endl; - stk.display(); - std::cout << "Assign back stk = stk1:" << std::endl; - stk = stk1; - stk.display(); + testConstructedStackIsEmpty(); + testConstructedStackIsEmpty(); + + testPush(); + testPop(); + testClear(); + + testCopyOfStackHasSameData(); + testPushingToCopyDoesNotChangeOriginal(); + testPoppingFromCopyDoesNotChangeOriginal(); + testPushingToOrginalDoesNotChangeCopy(); + testPoppingFromOrginalDoesNotChangeCopy(); + + testAssign(); + + std::cout << "All tests pass!\n"; return 0; } diff --git a/data_structures/test_stack_legacy.cpp b/data_structures/test_stack_legacy.cpp new file mode 100644 index 000000000..9a7cc18ff --- /dev/null +++ b/data_structures/test_stack_legacy.cpp @@ -0,0 +1,61 @@ +#include + +#include "./stack.hpp" + +int main() { + stack stk; + std::cout << "---------------------- Test construct ----------------------" + << std::endl; + stk.display(); + std::cout + << "---------------------- Test isEmptyStack ----------------------" + << std::endl; + if (stk.isEmptyStack()) { + std::cout << "PASS" << std::endl; + } else { + std::cout << "FAIL" << std::endl; + } + std::cout << "---------------------- Test push ----------------------" + << std::endl; + std::cout << "After pushing 10 20 30 40 into stack: " << std::endl; + stk.push(10); + stk.push(20); + stk.push(30); + stk.push(40); + stk.display(); + std::cout << "---------------------- Test top ----------------------" + << std::endl; + int value = stk.top(); + if (value == 40) { + std::cout << "PASS" << std::endl; + } else { + std::cout << "FAIL" << std::endl; + } + std::cout << "---------------------- Test pop ----------------------" + << std::endl; + stk.display(); + stk.pop(); + stk.pop(); + std::cout << "After popping 2 times: " << std::endl; + stk.display(); + std::cout << "---------------------- Test overload = operator " + "----------------------" + << std::endl; + stack stk1; + std::cout << "stk current: " << std::endl; + stk.display(); + std::cout << std::endl << "Assign stk1 = stk " << std::endl; + stk1 = stk; + stk1.display(); + std::cout << std::endl << "After pushing 8 9 10 into stk1:" << std::endl; + stk1.push(8); + stk1.push(9); + stk1.push(10); + stk1.display(); + std::cout << std::endl << "stk current: " << std::endl; + stk.display(); + std::cout << "Assign back stk = stk1:" << std::endl; + stk = stk1; + stk.display(); + return 0; +}