Back to Data Structures & Algorithms
2025-12-217 min read

Stack (Data Structures & Algorithms)

Learn Stack (Data Structures & Algorithms) step by step with clear examples and exercises.

Title: Deep Dive into Stacks (Data Structures & Algorithms) using Python

Why This Matters

Stacks are fundamental data structures in computer science, essential for problem-solving and understanding algorithms. They are crucial in programming interviews, real-world coding challenges, and debugging complex issues. In this lesson, we will explore the concept of stacks using Python examples, providing you with practical knowledge to tackle various problems confidently.

Stacks follow the Last In First Out (LIFO) principle, which is a key concept in understanding how algorithms work and how data structures can be manipulated to solve complex problems efficiently. Understanding stacks will help you develop strong problem-solving skills and prepare you for more advanced data structures like queues, trees, and graphs.

Prerequisites

Before diving into stacks, it's essential to have a solid understanding of the following concepts:

  1. Basic Python syntax and control structures (if-else, for loops, while loops)
  2. Data types (int, float, string, list, tuple, dictionary)
  3. Functions and methods in Python
  4. Understanding of recursion (optional but helpful)
  5. Familiarity with data structures like arrays and linked lists (optional but beneficial)

Core Concept

A stack is a linear data structure that follows the Last In First Out (LIFO) principle. It operates on the principles of pushing (adding an element to the top) and popping (removing an element from the top). The topmost element in the stack is called the peak or top element.

In Python, we can use lists, tuples, or even custom classes to implement a stack. Here's a simple implementation using a list:

class Stack:
def __init__(self):
self.items = []

def push(self, item):
self.items.append(item)

def pop(self):
if not self.is_empty():
return self.items.pop()

def peek(self):
if not self.is_empty():
return self.items[-1]

def is_empty(self):
return len(self.items) == 0

def size(self):
return len(self.items)

Stack using Tuples

Here's an implementation of a stack using tuples:

class Stack:
def __init__(self):
self.items = ()

def push(self, item):
self.items = self.items + (item,)

def pop(self):
if not self.is_empty():
return self.items[-1]
else:
raise IndexError("Pop from an empty stack")

def peek(self):
if not self.is_empty():
return self.items[-1]

def is_empty(self):
return len(self.items) == 0

def size(self):
return len(self.items)

Stack using Custom Classes

Here's an implementation of a stack using custom classes:

class Node:
def __init__(self, data=None):
self.data = data
self.next = None

class Stack:
def __init__(self):
self.top = None

def push(self, item):
new_node = Node(item)
if not self.is_empty():
new_node.next = self.top
self.top = new_node

def pop(self):
if not self.is_empty():
popped_data = self.top.data
self.top = self.top.next
return popped_data
else:
raise IndexError("Pop from an empty stack")

def peek(self):
if not self.is_empty():
return self.top.data

def is_empty(self):
return self.top is None

def size(self):
current = self.top
count = 0
while current:
count += 1
current = current.next
return count

Worked Example

Let's build a simple calculator using a stack to perform arithmetic operations like addition, subtraction, multiplication, and division.

class Calculator:
def __init__(self):
self.stack = Stack()

def input_tokens(self, expression):
tokens = expression.split()
for token in tokens:
if token.isnumeric():
self.stack.push(int(token))
elif token == '+':
b = self.stack.pop()
a = self.stack.pop()
self.stack.push(a + b)
elif token == '-':
b = self.stack.pop()
a = self.stack.pop()
self.stack.push(a - b)
elif token == '*':
b = self.stack.pop()
a = self.stack.pop()
self.stack.push(a * b)
elif token == '/':
b = self.stack.pop()
a = self.stack.pop()
if b != 0:
self.stack.push(a / b)
else:
raise ZeroDivisionError("Cannot divide by zero")
else:
raise ValueError(f"Invalid token '{token}'")
return self.stack.pop()

if __name__ == "__main__":
calculator = Calculator()
expression = "3 4 + 5 *"
print(calculator.input_tokens(expression)) # Output: 35

Common Mistakes

  1. Not checking if the stack is empty before popping: This can lead to IndexError: pop from an empty list. To avoid this, always check if the stack is empty before popping.
class Stack:
def pop(self):
if not self.is_empty():
return self.items.pop()
else:
raise IndexError("Pop from an empty stack")
  1. Not handling invalid input correctly: Make sure to handle unexpected tokens gracefully, like division by zero or unknown operators.
class Calculator:
def __init__(self):
self.stack = Stack()

... (rest of the code)

def input_tokens(self, expression):

try:

tokens = expression.split()

for token in tokens:

... (rest of the code)

except ValueError as e:

print(e)

except ZeroDivisionError as e:

print(e)


3. **Not properly handling operator precedence:** Make sure to handle operators with higher precedence before those with lower precedence. For example, in the calculator example above, multiplication and division should be performed before addition and subtraction.

4. **Not using the correct data structure for the problem at hand:** While stacks are great for problems that require LIFO operations, they may not always be the best choice. Make sure to consider other data structures like queues, trees, or graphs when appropriate.

Practice Questions

  1. Implement a stack using Python tuples instead of lists.
  2. Write a function to reverse a string using a stack in Python.
  3. Implement a postfix notation evaluator using a stack in Python.
  4. Given an arithmetic expression with parentheses, write a function that correctly calculates the result using a stack and handles operator precedence.
  5. Implement a custom Stack class using Python classes and methods.
  6. Write a function to check if a given string is balanced (i.e., has equal numbers of opening and closing brackets).
  7. Given an arithmetic expression without parentheses, write a function that correctly calculates the result using a stack and handles operator precedence.
  8. Implement a stack using Python classes and methods to perform depth-first search (DFS) on a graph.
  9. Write a function to implement the Tower of Hanoi problem using stacks in Python.
  10. Given an infix notation arithmetic expression, write a function that converts it into postfix notation using a stack in Python.

FAQ

  1. Why use a stack for postfix notation evaluation? Postfix notation (reverse Polish notation) eliminates the need for parentheses by placing operators after their operands. A stack can easily evaluate such expressions because it follows the LIFO principle, making it straightforward to perform operations on the correct operands in order.
  1. What are some real-world applications of stacks? Stacks are used in various areas like compiler design, parsing, and implementing undo/redo functionality in text editors and drawing applications. They also play a crucial role in debugging complex issues by helping developers track function calls and manage memory allocation efficiently.
  1. What is the time complexity of push and pop operations in Python's list-based stack? Both push and pop operations have an average time complexity of O(1) and worst-case time complexity of O(n), where n is the number of elements in the stack. However, in practice, lists are usually implemented as arrays with a fixed size, so the actual performance is closer to O(1).
  1. What is the difference between a stack and a queue? A stack follows the Last In First Out (LIFO) principle, while a queue follows the First In First Out (FIFO) principle. This means that elements added last in a stack are removed first, whereas elements added first in a queue are removed first.
  1. What is the difference between a stack and an array? An array is a data structure that stores elements of the same type in contiguous memory locations, while a stack is a data structure that follows the LIFO principle. An array does not enforce any specific order, whereas a stack enforces the LIFO order.
  1. What is the difference between a stack and a linked list? A linked list is a linear data structure where each element (node) contains a data part and a reference (link) to the next node in the sequence. In contrast, a stack stores its elements in contiguous memory locations, following the LIFO principle.
  1. Why would you use a custom Stack implementation instead of Python's built-in list? Custom implementations can provide additional functionality or optimizations not available in the built-in list implementation. For example, using linked lists for stacks allows for constant time push and pop operations even when the stack is very large.
  1. What is the relationship between stacks and recursion? Recursive functions often use a hidden stack to store function calls and their arguments. This hidden stack allows recursive functions to keep track of multiple nested function calls, making it possible to solve complex problems using recursion.
Stack (Data Structures & Algorithms) | Data Structures & Algorithms | XQA Learn