Stacks

They're like pancakes...

A stack is a data structure that works fairly intuitively. You have a stack of data that you can pull from.

Like a stack of pancakes, the first one on the plate is the last one to be eaten.

This type of system is known as “LIFO” or “last in first out”.

With stacks, you can only access the data on the top or bottom of the stack, but not both. You can either add to the stack or remove/delete the value that was most recently added.

For example, let’s look at the list: [ 1, 2, 3, 4 ]

start: [ 1, 2, 3, 4 ]
add zero: [ 0, 1, 2, 3, 4 ]
remove 3: [ 3, 4 ]

When we implement stacks, we use an internal data structure.

Here’s an example of a stack (with generic data) using a linked list behind the scenes:

// Defines a stack that uses a doubly-linked list as a data structure.
template <typename T>
class Stack {
 public:
  // default constructor
  Stack() : _ll{} {}
  // list constructor
  Stack(std::initializer_list<T> init_list) {
    for (const std::string& val : init_list)
      this->_ll.push_front(val);
  }
  // pushes a string to the top of the stack
  void push(T val) { this->_ll.push_front(val); }
  // pops off the top value in the stack
  void pop() { this->_ll.pop_front(); }
  // returns the data at the top of the stack
  T& top_data() { return this->_ll.front(); }
  // checks if the stack is empty (bool return value)
  bool is_empty() { return this->_ll.empty(); }
  // returns the size of the stack
  int size() { return this->_ll.size(); }
 private:
  LinkedList<T> _ll;
};

The way we used the linked list is with something called composition. It is a method of “reusing code”.

It is important to check to make sure that when we manipulate the stack, we are always within bounds and are not trying to access memory that does not exist. For me, I took care of the memory issues and bounds checking within my LinkedList class, however, this can be done in the Stack itself.