DEV Community

Cover image for Understanding Stack Data Structure: A Step-by-Step Guide to Implementing Stack in JavaScript
Emmanuel Ayinde
Emmanuel Ayinde

Posted on

Understanding Stack Data Structure: A Step-by-Step Guide to Implementing Stack in JavaScript

A Stack is a simple linear data structure that works like a stack of plates ๐Ÿฝ๏ธ. It follows the Last In, First Out (LIFO) principle. Think of it as a pile of plates: you can only add or remove plates from the top of the pile.

For a better understanding of stack, let's embark on a short journey of imagination ๐ŸŒŸ.
Imagine you're at a fancy restaurant ๐Ÿฝ๏ธ, and the kitchen staff is preparing for a busy night ๐Ÿ‘จโ€๐Ÿณ. In the dish area, there's a tall stack of plates waiting to be used. As diners arrive and orders pour in, the staff takes plates from the top of the stack. When clean plates are added, they go right on top. This simple system ensures that the plates at the bottom of the stack which have been there the longest are used last, while the freshly cleaned plates on top are used first โœจ.

stack data structure by Emmanuel Ayinde

This, in essence, is how a Stack data structure works. A Stack is a linear data structure that follows the Last In First Out (LIFO) principle. Just like with our stack of plates, the last item added to a Stack is the first one to be removed.

Table of Contents

In this comprehensive tutorial on the stack data structure, we'll explore the following topics with a simple, beginner-friendly approach:

  1. What is a Stack?
  2. Pros and Cons of Using Stack
  3. Real-World Applications of Stacks
  4. Key Operations on a Stack
  5. Stack Implementation in JavaScript
  6. Conclusion


Are you ready? Let's dive in

gif

What is a Stack?

A Stack is a linear data structure that follows the Last In, First Out (LIFO) principle. This means that the last element added to the stack will be the first one to be removed. Think of it like a stack of books: you can only add or remove books from the top of the stack.

Pros and Cons of Using Stack

Before we continue with the flow and write some codes, it is great to understanding where and where not to use Stack. The table below give an explicit Pros and Cons of Stack in details.

Pros Cons
Simple and easy to implement Limited access (only top element is directly accessible)
Efficient for Last-In-First-Out (LIFO) operations Not suitable for random access of elements
Constant time O(1) for push and pop operations Can lead to stack overflow if not managed properly
Useful for tracking state in algorithms (e.g., depth-first search) Not ideal for searching or accessing arbitrary elements
Helps in memory management (e.g., call stack in programming languages) Fixed size in some implementations (array-based stacks)
Useful for reversing data May require resizing in dynamic implementations, which can be costly
Supports recursive algorithms naturally Not efficient for large datasets that require frequent traversal
Helps in expression evaluation and syntax parsing Potential for underflow if pop operation is called on an empty stack
Useful in undo mechanisms in software Limited functionality compared to more complex data structures
Efficient for certain types of data organization (e.g., browser history) Not suitable for problems requiring queue-like (FIFO) behavior

Key Operations on a Stack

The fundamental operations that can be performed on a stack are:

  1. push(): Adds an element to the top of the stack.
  2. pop(): Removes the topmost element from the stack.
  3. peek(): Returns the top element of the stack without removing it.
  4. isEmpty(): Checks if the stack is empty.
  5. size(): Returns the number of elements in the stack.

Real-World Applications of Stacks

Stacks are every where in computer science and software development. Here are some common applications:

  1. Undo Functionality: In text editors or graphic design software, each action is pushed onto a stack. When you hit "undo," the most recent action is popped off the stack and reversed.

  2. Browser History: When you visit a new page, it's pushed onto a stack. The "back" button pops the current page off the stack, revealing the previous one.

  3. Function Call Stack: In programming languages, function calls are managed using a stack. When a function is called, it's pushed onto the call stack. When it returns, it's popped off.

  4. Expression Evaluation: Stacks are used to evaluate arithmetic expressions, especially those in postfix notation.

  5. Backtracking Algorithms: In problems like maze-solving or puzzle-solving, stacks can keep track of the path taken, allowing easy backtracking when needed.

Stack Implementation in JavaScript

Now, let's implement a Stack in JavaScript. It is important to know that there are different ways to implement a stack in JavaScript. One of the common ways to implement a stack is using array, another way is to use linked list. In this article, we'll implement a stack using linked list (singly linked list).

Implement Stack using Linked List

I hope you still remember how linked list works? You might need to check out the linked list implementation in one of our previous articles in this same series.

Now, let's start implementing our stack using singly linked list. Shall we?

gif

First, we'll create a Node class to represent our stack individual item.

class Node {
  constructor(data) {
    this.data = data;
    this.next = null;
  }
}
Enter fullscreen mode Exit fullscreen mode

Then, we'll create a Stack class to represent our stack.

class Stack {
  constructor() {
    this.top = null;
    this.size = 0;
  }

  // Stack Operations will be implemented here ๐Ÿ‘‡
}
Enter fullscreen mode Exit fullscreen mode

Push Operation

The push operation adds a new element to the top of the stack. It creates a new StackNode, sets its next pointer to the current top, and then updates top to point to this new node. Finally, it increments the size.

  // Push element to the top of the stack
  push(element) {
    const newNode = new Node(element);
    newNode.next = this.top;
    this.top = newNode;
    this.size++;
  }
Enter fullscreen mode Exit fullscreen mode

Pop Operation

The pop operation removes the topmost element from the stack. It first checks if the stack is empty. If it is, it returns an error message. Otherwise, it removes the top element, updates the top pointer to the next node, and decrements the size. Finally, it returns the removed element.

  // Remove and return the top element
  pop() {
    if (this.isEmpty()) {
      return "Stack is empty";
    }
    const poppedElement = this.top.data;
    this.top = this.top.next;
    this.size--;
    return poppedElement;
  }
Enter fullscreen mode Exit fullscreen mode

Peek Operation

The peek operation returns the top element without removing it. It first checks if the stack is empty. If it is, it returns an error message. Otherwise, it returns the data of the top element.

  // Return the top element without removing it
  peek() {
    if (this.isEmpty()) {
      return "Stack is empty";
    }
    return this.top.data;
  }
Enter fullscreen mode Exit fullscreen mode

isEmpty Operation

The isEmpty operation checks if the stack is empty. It returns true if the stack is empty, and false otherwise.

  // Check if the stack is empty
  isEmpty() {
    return this.size === 0;
  }
Enter fullscreen mode Exit fullscreen mode

getSize Operation

The getSize operation returns the size of the stack. It returns the number of elements in the stack.

  // Return the size of the stack
  getSize() {
    return this.size;
  }
Enter fullscreen mode Exit fullscreen mode

Print Operation

The print operation prints the stack. It returns the data of the top element.

  // Print the stack
  print() {
    let current = this.top;
    let result = "";
    while (current) {
      result += current.data + " ";
      current = current.next;
    }
    console.log(result.trim());
  }
Enter fullscreen mode Exit fullscreen mode

Usage Example

// Usage example
const customStack = new CustomStack();
customStack.push(10);
customStack.push(20);
customStack.push(30);
console.log(customStack.pop()); // 30
console.log(customStack.peek()); // 20
console.log(customStack.getSize()); // 2
console.log(customStack.isEmpty()); // false
customStack.print(); // 20 10
Enter fullscreen mode Exit fullscreen mode

In this implementation, we used a linked list (singly linked list) structure to represent our stack. Each element is a Node with a data value and a reference to the next Node. The top of the stack is always the most recently added Node.

Conclusion

Stacks are a fundamental data structure in computer science that follow the Last In, First Out (LIFO) principle. They are used in various applications, including managing function calls, implementing undo functionality, and evaluating arithmetic expressions.

In this tutorial, we've covered the basics of stacks, pros and cons of using them, and their implementation in JavaScript (using linked list). Understanding stacks is not just about knowing how to implement them, but also recognizing when they're the right tool for solving a problem.

As you continue your journey in software development, you'll find that stacks are an indispensable tool in your problem-solving toolkit. They're simple yet powerful, and mastering them will significantly enhance your ability to design efficient algorithms and data structures.



Stay Updated and Connected

To ensure you don't miss any part of this series and to connect with me for more in-depth discussions on Software Development (Web, Server, Mobile or Scraping / Automation), data structures and algorithms, and other exciting tech topics, follow me on:

Stay tuned and happy coding ๐Ÿ‘จโ€๐Ÿ’ป๐Ÿš€


Enter fullscreen mode Exit fullscreen mode

Top comments (0)