12.07 Dynamic Node Allocation in Stack Implementations
Executive Summary: Implementing a node-based dynamic stack, analyzing push/pop pointer manipulation and cleanup.
💻 1. Annotated Source Code
#ifndef STACK_H #define STACK_H class Stack { public: virtual void push(int newEntry) = 0; virtual int pop() = 0; virtual int peek() const = 0; virtual bool isEmpty() const = 0; virtual void makeEmpty() = 0; }; #endif
#include "Stack.h" #include <iostream> using namespace std; //------------------- Node ------------------------// class Node { public: Node(int data, Node* next) : data(data), next(next) {} int getData() const { return data; } void setData(int data) { this->data = data; } Node* getNext() const { return next; } void setNext(Node* next) { this->next = next; } private: int data; Node* next; }; //------------------ LinkedStack ------------------------// class LinkedStack : public Stack { public: LinkedStack() : top(nullptr) {} //end ctor virtual ~LinkedStack() { makeEmpty(); }//end dtor void push(int newEntry) override { Node* newNode = new Node(newEntry, top); top = newNode; }//end push int pop() override { if (isEmpty()) { cout << "You cannot pop on an empty stack!" << endl; return 0; } Node* temp = top; int data = temp->getData(); top = top->getNext(); delete temp; temp = nullptr; return data; }//end pop int peek() const override { if (isEmpty()) { cout << "You cannot peek on an empty stack!" << endl; return 0; } return top->getData(); }//end peek bool isEmpty() const override { return top == nullptr; }//end isEmpty void makeEmpty() override { while (top != nullptr) { Node* temp = top; top = top->getNext(); delete temp; } }//end makeEmpty private: Node* top; };
#include <iostream> #include "LinkedStack.h" using namespace std; void printStack(LinkedStack& stack); int main() { LinkedStack stack; stack.push(100); stack.push(150); stack.push(222); stack.push(71); stack.push(53); stack.push(125); printStack(stack); cout << "Again to verify it's intact:" << endl; printStack(stack); //cout << "Top of stack is: " << stack.peek() << endl; //while (!stack.isEmpty()) { // cout << stack.pop() << endl; //} return 0; } void printStack(LinkedStack& stack) { LinkedStack temp; int data; while (!stack.isEmpty()) { data = stack.pop(); cout << data << endl; temp.push(data); }//end while while (!temp.isEmpty()) { stack.push(temp.pop()); } }//end printStack
📐 2. Architecture & UML Class Model
<<struct>>
StackNode<T>
Stack Node
Attributes / Data Members
+item : T
+next : StackNode<T>*
<<template class>>
LinkedStack<T>
Dynamic LIFO Stack
Attributes / Data Members
-topPtr : StackNode<T>*
Operations / Methods
+LinkedStack()
+~LinkedStack()
+push(newEntry: const T&) : bool[O(1)]
+pop() : bool[O(1)]
+peek() : T const[O(1)]
+isEmpty() : bool const
🔗 Architectural Relationships & Hierarchy
LinkedStack<T>
◆──
pushes onto topPtr
◆──
StackNode<T>
📚 3. Core C++ Concepts Deep-Dive
Node Stack Mechanics
Pushing creates a node and prepends it to the top pointer; popping frees the head node.
⚡ 4. Embedded Systems & Hardware Reality
Memory Comparison
Array stacks use contiguous static memory and outperform linked stacks across all embedded metrics.
💡 5. Production-Ready Embedded Refactoring
💡 Production-Ready Refactor
// Static array stack is universally preferred in microcontrollers
📝 Knowledge Verification Quiz
Test your understanding of the C++ concepts and embedded microcontroller trade-offs covered in this guide. Click any option for instant feedback.
Q1. What operation is required on every pop() in a LinkedStack?
Detailed Explanation:
Popping removes the head node, requiring explicit deallocation to avoid memory leakage.