Back to Data Structures & Algorithms
2026-02-188 min read

stacks (Data Structures & Algorithms)

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

Why This Matters

Welcome to our full guide on stacks, a fundamental data structure in computer science and programming. In this lesson, we will delve deep into the concept of stacks, their significance, and how to implement them using Python. By the end, you'll be well-prepared to tackle real-world problems that necessitate stack usage.

Stacks are essential for understanding various algorithms and data structures, as they form the basis for many problem-solving techniques. They help manage function calls during program execution, facilitate recursion, and enable undo/redo operations in text editors and web browsers.

Prerequisites

To fully grasp this lesson, it is essential to have a solid understanding of the following topics:

  1. Basic Python syntax (variables, operators, loops, and functions)
  2. Data structures (lists, tuples, dictionaries, and sets)
  3. Control flow statements (if-else, for loops, while loops, and conditional expressions)
  4. Functions and function scopes
  5. Exception handling
  6. Basic mathematical operations
  7. Understanding of lists and their methods in Python
  8. Recursion basics
  9. Familiarity with common algorithms and data structures concepts

Core Concept

A stack is a linear data structure that follows the Last In, First Out (LIFO) principle. It's like a pile of dishes where the last plate added to the top will be the first one taken out from the top. This makes stacks particularly useful for handling function calls, recursion, and undo/redo operations in programming.

Stack Operations

A stack supports four primary operations:

  1. Push: Adds an element to the top of the stack
  2. Pop: Removes an element from the top of the stack
  3. Peek: Returns the topmost element without removing it (not a built-in operation in Python, but can be implemented using indexing)
  4. Size: Returns the number of elements in the stack
  5. Empty: Checks if the stack is empty or not
  6. Top: Returns the topmost element but does not remove it (added as a separate function for clarity)

Implementing a Stack in Python

Python provides a built-in data structure called list that can be used as a stack, as lists support push and pop operations directly. However, for better organization and code reusability, we will create a custom Stack class:

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 size(self):
return len(self.items)

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

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

Now you can create a stack and perform operations like this:

my_stack = Stack()
my_stack.push("apple")
my_stack.push("banana")
print(my_stack.peek()) # Output: banana
my_stack.pop()
print(my_stack.peek()) # Output: apple

Worked Example

Let's solve a classic problem using stacks: evaluating postfix expressions. A postfix expression is a mathematical expression where operators come after their operands, such as 3 4 +. We can use a stack to perform the operations in the correct order.

def evaluate_postfix(expression):
stack = Stack()

for token in expression:
if token.isdigit():
stack.push(int(token))
else:
right_operand = stack.pop()
left_operand = stack.pop()
result = eval(f"{left_operand} {token} {right_operand}")
stack.push(result)

return stack.peek()

print(evaluate_postfix("3 4 +")) # Output: 7

Common Mistakes

  1. Forgetting to handle division by zero error
  • Implement a check for zero before performing the division operation
  1. Not properly handling operator precedence when building the postfix expression
  • Use parentheses to group expressions and ensure correct order of operations
  1. Using a list instead of a stack for the actual implementation, leading to incorrect order of operations
  • Always use the custom Stack class for proper LIFO behavior
  1. Failing to account for negative numbers and parentheses in expressions
  • Make sure to handle both positive and negative numbers, as well as nested parentheses
  1. Improper error handling when encountering invalid characters or expressions
  • Implement exception handling to catch errors gracefully and provide meaningful feedback
  1. Inefficient implementation of stack operations (e.g., using list slicing for peek operation)
  • Use list indexing instead of slicing for better performance
  1. Not considering the maximum size of the stack when dealing with large expressions
  • Implement a resizable stack or handle out-of-memory errors appropriately
  1. Misunderstanding the concept of LIFO and applying it incorrectly to problems that require FIFO behavior (such as breadth-first search)
  2. Assuming that all Python lists behave like stacks, leading to unexpected results when popping elements from the wrong end of the list
  3. Not considering the efficiency of stack operations in different data structures (e.g., linked lists vs. arrays) and choosing an inappropriate implementation for a given problem

Practice Questions

  1. Implement a function that checks if a given string is a valid postfix expression.
  • Check for proper syntax, operator precedence, and absence of invalid characters
  1. Given a set of parentheses, write a function that uses a stack to determine if the input is balanced.
  • Keep track of opening and closing parentheses using a stack and check for matching pairs
  1. Write a function that evaluates infix expressions using stacks and a recursive parser for handling parentheses.
  • Convert the infix expression to postfix, parse it using a stack, and evaluate the result
  1. Implement a depth-first search (DFS) algorithm using a stack to traverse a graph
  2. Write a function that uses a stack to implement a simple calculator for infix expressions with parentheses, operators, and numbers
  3. Implement a function that implements the Tower of Hanoi problem using stacks
  4. Given a list of brackets representing nested structures, write a function that checks if the input is valid (using a stack)
  5. Write a function that uses a stack to implement a simple undo/redo system for text editing operations
  6. Implement a function that uses a stack to solve the problem of finding the longest valid parentheses sequence in an expression with multiple nested sequences
  7. Write a function that uses a stack to solve the problem of evaluating infix expressions that contain variables and constants, using a symbol table for variable lookup

FAQ

  • Stacks follow the LIFO principle, which makes them ideal for situations where the order in which items are removed is important, such as function calls and recursion. Queues, on the other hand, follow the First In, First Out (FIFO) principle, making them suitable for tasks like breadth-first search or producing output in the same order as input.

Can I implement a stack using Python's built-in deque data structure?

  • Yes, you can use Python's collections.deque to create a stack by always appending and removing from the right side of the deque. However, it may not be as efficient for certain operations like peek, size, and is_empty compared to using a list.

How does Python handle function calls with regards to stacks?

  • When a function is called in Python, its local variables are pushed onto the stack, and when the function returns, those variables are popped off the stack. This allows for proper management of memory during runtime.

What is the time complexity of common stack operations in Python's list implementation?

  • Push, pop, peek, size, and is_empty all have a time complexity of O(1) in Python's list implementation, making it an efficient choice for implementing stacks. However, keep in mind that this assumes constant-time access to memory, which may not always be the case due to cache effects or other factors.

How can I implement a stack using linked lists instead of arrays?

  • Implement a Node class with a data attribute and a reference to the next node. Create a Stack class that maintains a reference to the top node, and provide methods for push, pop, peek, size, and is_empty operations accordingly. This will allow for dynamic resizing of the stack as elements are added or removed.

Is it possible to implement a stack using a dictionary in Python?

  • While a dictionary can be used to simulate a stack by treating keys as indices and values as elements, this approach may not provide the same performance benefits as using lists or linked lists due to the time complexity of dictionary operations (O(1) for accessing an element by key, but O(n) for iterating over all keys).

What is the difference between a stack and a queue in terms of their applications?

  • Stacks are primarily used in situations where the last item added is the first one to be removed (e.g., function calls, recursion, undo/redo operations), while queues are used when items should be processed in the order they were added (e.g., breadth-first search, producing output in FIFO order).

Can I use a stack to solve problems that require FIFO behavior?

  • While it is possible to use a stack for some FIFO problems by reversing the order of operations or manipulating the stack appropriately, it may not always be the most efficient solution. In such cases, it's better to use a queue or another data structure more suited to FIFO tasks.

How can I optimize my stack implementation for large datasets?

  • To handle large datasets efficiently, consider using a resizable stack (e.g., dynamic arrays or linked lists) that can grow and shrink as needed. Additionally, you may want to implement lazy initialization (i.e., only creating the stack when it's actually needed) to conserve memory.

What are some common algorithms that make use of stacks?

  • Many algorithms rely on stacks for their correct functioning, such as postfix expression evaluation, depth-first search, topological sorting, and backtracking algorithms (e.g., the Knapsack problem or the N-Queens problem).
stacks (Data Structures & Algorithms) | Data Structures & Algorithms | XQA Learn