mirror of
https://github.com/TheAlgorithms/C-Plus-Plus.git
synced 2026-05-09 07:32:54 +08:00
refactor: use std::shared_ptr
This commit is contained in:
@@ -8,87 +8,60 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
/** 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 <class Type>
|
||||
template <class ValueType>
|
||||
struct node {
|
||||
Type data; ///< data at current node
|
||||
node<Type> *next; ///< pointer to the next ::node instance
|
||||
ValueType data = {}; ///< data at current node
|
||||
std::shared_ptr<node<ValueType>> next =
|
||||
{}; ///< pointer to the next ::node instance
|
||||
};
|
||||
|
||||
template <typename Node, typename Action>
|
||||
void traverse(const std::shared_ptr<Node>& 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 <class Type>
|
||||
template <class ValueType>
|
||||
class stack {
|
||||
public:
|
||||
using value_type = ValueType;
|
||||
|
||||
/** Show stack */
|
||||
void display() {
|
||||
node<Type> *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<Type> &otherStack) {
|
||||
node<Type> *newNode, *current, *last;
|
||||
|
||||
if (otherStack.stackTop == nullptr) {
|
||||
stackTop = nullptr;
|
||||
} else {
|
||||
current = otherStack.stackTop;
|
||||
stackTop = new node<Type>;
|
||||
stackTop->data = current->data;
|
||||
stackTop->next = nullptr;
|
||||
last = stackTop;
|
||||
current = current->next;
|
||||
/* Copy the remaining stack */
|
||||
while (current != nullptr) {
|
||||
newNode = new node<Type>;
|
||||
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<value_type> 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<Type> *newNode;
|
||||
newNode = new node<Type>;
|
||||
void push(const value_type& item) {
|
||||
auto newNode = std::make_shared<node<value_type>>();
|
||||
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<Type> *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<Type> &operator=(const stack<Type> &otherStack) {
|
||||
node<Type> *newNode, *current, *last;
|
||||
|
||||
deleteAllNodes();
|
||||
if (otherStack.stackTop == nullptr) {
|
||||
stackTop = nullptr;
|
||||
} else {
|
||||
current = otherStack.stackTop;
|
||||
stackTop = new node<Type>;
|
||||
stackTop->data = current->data;
|
||||
stackTop->next = nullptr;
|
||||
last = stackTop;
|
||||
current = current->next;
|
||||
/* Copy the remaining stack */
|
||||
while (current != nullptr) {
|
||||
newNode = new node<Type>;
|
||||
newNode->data = current->data;
|
||||
newNode->next = nullptr;
|
||||
last->next = newNode;
|
||||
last = newNode;
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
size = otherStack.size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
node<Type> *stackTop; /**< Pointer to the stack */
|
||||
int size; ///< size of stack
|
||||
std::shared_ptr<node<value_type>> stackTop = {}; /**< Pointer to the stack */
|
||||
std::size_t size = 0; ///< size of stack
|
||||
};
|
||||
|
||||
#endif // DATA_STRUCTURES_STACK_HPP_
|
||||
|
||||
@@ -1,61 +1,188 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "./stack.hpp"
|
||||
|
||||
void assertTrue(const bool inValue) {
|
||||
if (!inValue) {
|
||||
std::cout << "Assertion fails!\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void assertEqual(const T& valA, const T& valB) {
|
||||
assertTrue(valA == valB);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void testConstructedStackIsEmpty() {
|
||||
stack<T> curStack;
|
||||
assertTrue(curStack.isEmptyStack());
|
||||
}
|
||||
|
||||
void testPush() {
|
||||
using valueType = int;
|
||||
stack<valueType> curStack;
|
||||
curStack.push(10);
|
||||
curStack.push(20);
|
||||
curStack.push(30);
|
||||
curStack.push(40);
|
||||
const auto expectedData = std::vector<valueType>({40, 30, 20, 10});
|
||||
assertEqual(curStack.toVector(), expectedData);
|
||||
}
|
||||
|
||||
void testTop() {
|
||||
using valueType = unsigned;
|
||||
stack<valueType> curStack;
|
||||
curStack.push(1);
|
||||
curStack.push(2);
|
||||
curStack.push(3);
|
||||
curStack.push(4);
|
||||
assertEqual(curStack.top(), static_cast<valueType>(4));
|
||||
}
|
||||
|
||||
void testPop() {
|
||||
using valueType = int;
|
||||
stack<valueType> curStack;
|
||||
curStack.push(100);
|
||||
curStack.push(200);
|
||||
curStack.push(300);
|
||||
|
||||
assertEqual(curStack.top(), static_cast<valueType>(300));
|
||||
curStack.pop();
|
||||
assertEqual(curStack.top(), static_cast<valueType>(200));
|
||||
curStack.pop();
|
||||
assertEqual(curStack.top(), static_cast<valueType>(100));
|
||||
curStack.pop();
|
||||
assertTrue(curStack.isEmptyStack());
|
||||
}
|
||||
|
||||
void testClear() {
|
||||
stack<int> curStack;
|
||||
curStack.push(1000);
|
||||
curStack.push(2000);
|
||||
curStack.clear();
|
||||
assertTrue(curStack.isEmptyStack());
|
||||
}
|
||||
|
||||
void testCopyOfStackHasSameData() {
|
||||
stack<int> 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<valueType> stackA;
|
||||
stackA.push(10);
|
||||
stackA.push(20);
|
||||
stackA.push(30);
|
||||
auto stackB(stackA);
|
||||
stackB.push(40);
|
||||
|
||||
const auto expectedDataA = std::vector<valueType>({30, 20, 10});
|
||||
const auto expectedDataB = std::vector<valueType>({40, 30, 20, 10});
|
||||
|
||||
assertEqual(stackA.toVector(), expectedDataA);
|
||||
assertEqual(stackB.toVector(), expectedDataB);
|
||||
}
|
||||
|
||||
void testPoppingFromCopyDoesNotChangeOriginal() {
|
||||
using valueType = int;
|
||||
stack<valueType> stackA;
|
||||
stackA.push(10);
|
||||
stackA.push(20);
|
||||
stackA.push(30);
|
||||
auto stackB(stackA);
|
||||
stackB.pop();
|
||||
|
||||
const auto expectedDataA = std::vector<valueType>({30, 20, 10});
|
||||
const auto expectedDataB = std::vector<valueType>({20, 10});
|
||||
|
||||
assertEqual(stackA.toVector(), expectedDataA);
|
||||
assertEqual(stackB.toVector(), expectedDataB);
|
||||
}
|
||||
|
||||
void testPushingToOrginalDoesNotChangeCopy() {
|
||||
using valueType = int;
|
||||
stack<valueType> stackA;
|
||||
stackA.push(10);
|
||||
stackA.push(20);
|
||||
stackA.push(30);
|
||||
const auto stackB(stackA);
|
||||
stackA.push(40);
|
||||
|
||||
const auto expectedDataA = std::vector<valueType>({40, 30, 20, 10});
|
||||
const auto expectedDataB = std::vector<valueType>({30, 20, 10});
|
||||
|
||||
assertEqual(stackA.toVector(), expectedDataA);
|
||||
assertEqual(stackB.toVector(), expectedDataB);
|
||||
}
|
||||
|
||||
void testPoppingFromOrginalDoesNotChangeCopy() {
|
||||
using valueType = int;
|
||||
stack<valueType> stackA;
|
||||
stackA.push(10);
|
||||
stackA.push(20);
|
||||
stackA.push(30);
|
||||
const auto stackB(stackA);
|
||||
stackA.pop();
|
||||
|
||||
const auto expectedDataA = std::vector<valueType>({20, 10});
|
||||
const auto expectedDataB = std::vector<valueType>({30, 20, 10});
|
||||
|
||||
assertEqual(stackA.toVector(), expectedDataA);
|
||||
assertEqual(stackB.toVector(), expectedDataB);
|
||||
}
|
||||
|
||||
void testAssign() {
|
||||
using valueType = int;
|
||||
stack<valueType> stackA;
|
||||
stackA.push(10);
|
||||
stackA.push(20);
|
||||
stackA.push(30);
|
||||
stack<valueType> stackB = stackA;
|
||||
stackA.pop();
|
||||
stackB.push(40);
|
||||
|
||||
const auto expectedDataA = std::vector<valueType>({20, 10});
|
||||
const auto expectedDataB = std::vector<valueType>({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<valueType>({10});
|
||||
const auto otherExpectedDataB = std::vector<valueType>({6, 5, 20, 10});
|
||||
|
||||
assertEqual(stackA.toVector(), otherExpectedDataA);
|
||||
assertEqual(stackB.toVector(), otherExpectedDataB);
|
||||
}
|
||||
|
||||
int main() {
|
||||
stack<int> 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<int> 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<int>();
|
||||
testConstructedStackIsEmpty<char>();
|
||||
|
||||
testPush();
|
||||
testPop();
|
||||
testClear();
|
||||
|
||||
testCopyOfStackHasSameData();
|
||||
testPushingToCopyDoesNotChangeOriginal();
|
||||
testPoppingFromCopyDoesNotChangeOriginal();
|
||||
testPushingToOrginalDoesNotChangeCopy();
|
||||
testPoppingFromOrginalDoesNotChangeCopy();
|
||||
|
||||
testAssign();
|
||||
|
||||
std::cout << "All tests pass!\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
61
data_structures/test_stack_legacy.cpp
Normal file
61
data_structures/test_stack_legacy.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "./stack.hpp"
|
||||
|
||||
int main() {
|
||||
stack<int> 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<int> 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;
|
||||
}
|
||||
Reference in New Issue
Block a user