Stacks and Queues

πŸ“– Introduction

Stacks and queues are deceptively simple data structures that power some of the most important operations in computing. The browser's back button? A stack. Job scheduling in operating systems? Queues. Parsing expressions in compilers? Stacks again.

In my projects, I've used stacks for undo/redo functionality, queues for task processing pipelines, and monotonic stacks for optimizing range queries. Understanding these structures deeplyβ€”especially their variations like deques and priority queuesβ€”opens up elegant solutions to problems that would otherwise require complex logic.


🎯 Stack: Last In, First Out (LIFO)

A stack is a linear data structure where elements are added and removed from the same end (the "top").

Visual Representation

spinner

Stack Implementation

from typing import Optional, Generic, TypeVar

T = TypeVar('T')


class Stack(Generic[T]):
    """
    Stack implementation using Python list.
    All operations O(1) amortized.
    """
    
    def __init__(self):
        self._items: list[T] = []
    
    def push(self, item: T) -> None:
        """Add item to top. O(1) amortized."""
        self._items.append(item)
    
    def pop(self) -> T:
        """Remove and return top item. O(1)."""
        if self.is_empty():
            raise IndexError("Pop from empty stack")
        return self._items.pop()
    
    def peek(self) -> T:
        """Return top item without removing. O(1)."""
        if self.is_empty():
            raise IndexError("Peek at empty stack")
        return self._items[-1]
    
    def is_empty(self) -> bool:
        """Check if stack is empty. O(1)."""
        return len(self._items) == 0
    
    def size(self) -> int:
        """Return number of items. O(1)."""
        return len(self._items)
    
    def __len__(self) -> int:
        return self.size()
    
    def __str__(self) -> str:
        return f"Stack({self._items})"


# Usage
stack = Stack()
stack.push(1)
stack.push(2)
stack.push(3)
print(stack.peek())  # 3
print(stack.pop())   # 3
print(stack.pop())   # 2

Stack Using Linked List


πŸ“š Queue: First In, First Out (FIFO)

A queue is a linear data structure where elements are added at one end (rear) and removed from the other (front).

Visual Representation

spinner

Queue Implementation with Deque

Circular Queue (Fixed Size)


πŸ”„ Deque: Double-Ended Queue

A deque (pronounced "deck") allows O(1) operations at both ends.

Implementing Deque


πŸ“Š Stack Applications

Valid Parentheses

Evaluate Reverse Polish Notation

Min Stack

Daily Temperatures (Monotonic Stack)


πŸ“ˆ Monotonic Stack

A monotonic stack maintains elements in sorted order (either increasing or decreasing).

spinner

Next Greater Element

Largest Rectangle in Histogram

Trapping Rain Water


πŸ“Š Queue Applications

BFS (Level Order Traversal)

Sliding Window Maximum

Task Scheduler


⭐ Priority Queue

A priority queue returns elements in priority order, not insertion order.

Kth Largest Element

Merge K Sorted Lists


πŸ“ Practice Exercises

Exercise 1: Implement Queue Using Stacks

chevron-rightSolutionhashtag

Exercise 2: Implement Stack Using Queues

chevron-rightSolutionhashtag

Exercise 3: Simplify Path

chevron-rightSolutionhashtag

πŸ”‘ Key Takeaways

  1. Stack = LIFO; Queue = FIFO

  2. Deque provides O(1) at both endsβ€”use collections.deque

  3. Monotonic stacks solve "next greater/smaller" problems

  4. Priority queues (heaps) give O(log n) min/max access

  5. BFS uses queues; DFS uses stacks

  6. Two stacks can implement a queue, and vice versa


πŸš€ What's Next?

In the next article, we'll explore hash tables:

  • Hash function design

  • Collision resolution strategies

  • Python dict internals

  • Common hash table problems

Next: Article 7 - Hash Tables


πŸ“š References

  • Python collections.deque documentation

  • Python heapq documentation

  • "Cracking the Coding Interview" - Stacks and Queues

Last updated