foreach-ui logo
codeLanguages
account_treeDSA

Quick Actions

quizlock Random Quiz
trending_uplock Progress
  • 1
  • 2
  • 3
  • 4
  • quiz
Python
  • Understand stack operations and LIFO principle
  • Master queue operations and FIFO principle
  • Implement stacks and queues using lists and deques
  • Apply stacks and queues in real-world scenarios

Stacks, Queues, and Deques

Introduction

Imagine you're at a busy coffee shop. Customers arrive and form a line - the first person to arrive gets served first. This is a queue. Now imagine stacking plates in a cafeteria - you can only take the top plate, and new plates are placed on top. This is a stack.

These simple concepts power everything from web browsers to operating systems. Understanding stacks and queues is like learning the basic grammar of computer science - they appear everywhere once you know to look for them.


Stacks: Last In, First Out (LIFO)

A stack is like a stack of books or cafeteria trays. You can only access the top item, and new items are always placed on top.

Stack Operations

# Using a list as a stack
stack = []

# Push (add to top)
stack.append('book1')
stack.append('book2')
stack.append('book3')
print(stack)  # ['book1', 'book2', 'book3']

# Pop (remove from top)
top_book = stack.pop()
print(top_book)  # 'book3'
print(stack)     # ['book1', 'book2']

# Peek (look at top without removing)
if stack:
    print(f"Top book: {stack[-1]}")  # 'book2'

Stack Implementation

class Stack:
    def __init__(self):
        self.items = []
    
    def push(self, item):
        """Add item to top of stack."""
        self.items.append(item)
    
    def pop(self):
        """Remove and return item from top of stack."""
        if self.is_empty():
            raise IndexError("Pop from empty stack")
        return self.items.pop()
    
    def peek(self):
        """Return top item without removing it."""
        if self.is_empty():
            raise IndexError("Peek from empty stack")
        return self.items[-1]
    
    def is_empty(self):
        """Check if stack is empty."""
        return len(self.items) == 0
    
    def size(self):
        """Return number of items in stack."""
        return len(self.items)

# Usage
book_stack = Stack()
book_stack.push("Harry Potter")
book_stack.push("Lord of the Rings")
book_stack.push("The Hobbit")

print(book_stack.peek())  # "The Hobbit"
print(book_stack.pop())   # "The Hobbit"
print(book_stack.size())  # 2

Queues: First In, First Out (FIFO)

A queue is like a line at a store or restaurant. The first person to arrive is the first to be served.

Queue Operations

# Using a list as a queue (inefficient)
queue = []

# Enqueue (add to back)
queue.append('customer1')
queue.append('customer2')
queue.append('customer3')
print(queue)  # ['customer1', 'customer2', 'customer3']

# Dequeue (remove from front) - inefficient with lists
front_customer = queue.pop(0)
print(front_customer)  # 'customer1'
print(queue)          # ['customer2', 'customer3']

Efficient Queue with Deque

from collections import deque

class Queue:
    def __init__(self):
        self.items = deque()
    
    def enqueue(self, item):
        """Add item to back of queue."""
        self.items.append(item)
    
    def dequeue(self):
        """Remove and return item from front of queue."""
        if self.is_empty():
            raise IndexError("Dequeue from empty queue")
        return self.items.popleft()
    
    def peek(self):
        """Return front item without removing it."""
        if self.is_empty():
            raise IndexError("Peek from empty queue")
        return self.items[0]
    
    def is_empty(self):
        """Check if queue is empty."""
        return len(self.items) == 0
    
    def size(self):
        """Return number of items in queue."""
        return len(self.items)

# Usage
checkout_line = Queue()
checkout_line.enqueue("Alice")
checkout_line.enqueue("Bob")
checkout_line.enqueue("Charlie")

print(checkout_line.peek())    # "Alice"
print(checkout_line.dequeue()) # "Alice"
print(checkout_line.size())    # 2

Deques: Double-Ended Queues

A deque (pronounced "deck") allows efficient operations from both ends. It's like having doors at both ends of a tunnel.

Deque Operations

from collections import deque

# Create a deque
numbers = deque([1, 2, 3, 4, 5])

# Add to right (end)
numbers.append(6)      # [1, 2, 3, 4, 5, 6]

# Add to left (beginning)
numbers.appendleft(0)  # [0, 1, 2, 3, 4, 5, 6]

# Remove from right
right = numbers.pop()      # 6, deque([0, 1, 2, 3, 4, 5])

# Remove from left
left = numbers.popleft()   # 0, deque([1, 2, 3, 4, 5])

# Peek operations
print(numbers[0])     # 1 (leftmost)
print(numbers[-1])    # 5 (rightmost)

Deque as Stack and Queue

# As a stack (LIFO)
stack = deque()
stack.append('bottom')
stack.append('middle') 
stack.append('top')
print(stack.pop())  # 'top'

# As a queue (FIFO)
queue = deque()
queue.append('first')
queue.append('second')
queue.append('third')
print(queue.popleft())  # 'first'

Real-World Applications

Browser History (Stack)

class BrowserHistory:
    def __init__(self):
        self.history = []
        self.current = -1
    
    def visit(self, url):
        """Visit a new URL."""
        # Remove forward history when visiting new page
        self.history = self.history[:self.current + 1]
        self.history.append(url)
        self.current += 1
    
    def back(self):
        """Go back to previous page."""
        if self.current > 0:
            self.current -= 1
            return self.history[self.current]
        return None
    
    def forward(self):
        """Go forward to next page."""
        if self.current < len(self.history) - 1:
            self.current += 1
            return self.history[self.current]
        return None

# Usage
browser = BrowserHistory()
browser.visit("google.com")
browser.visit("stackoverflow.com")
browser.visit("github.com")

print(browser.back())    # "stackoverflow.com"
print(browser.back())    # "google.com"
print(browser.forward()) # "stackoverflow.com"

Print Queue (Queue)

from collections import deque

class PrintQueue:
    def __init__(self):
        self.queue = deque()
    
    def add_job(self, document_name, user):
        """Add a print job to the queue."""
        job = {"document": document_name, "user": user, "timestamp": time.time()}
        self.queue.append(job)
        print(f"Added print job: {document_name} for {user}")
    
    def process_job(self):
        """Process the next print job."""
        if self.queue:
            job = self.queue.popleft()
            print(f"Printing: {job['document']} for {job['user']}")
            return job
        else:
            print("No jobs in queue")
            return None
    
    def show_queue(self):
        """Show all pending jobs."""
        if not self.queue:
            print("Print queue is empty")
        else:
            print("Pending print jobs:")
            for i, job in enumerate(self.queue, 1):
                print(f"{i}. {job['document']} - {job['user']}")

# Usage
printer = PrintQueue()
printer.add_job("report.pdf", "Alice")
printer.add_job("presentation.pptx", "Bob")
printer.add_job("resume.docx", "Charlie")

printer.show_queue()
printer.process_job()
printer.process_job()

Text Editor Undo/Redo (Two Stacks)

class TextEditor:
    def __init__(self):
        self.text = ""
        self.undo_stack = []
        self.redo_stack = []
    
    def type_text(self, new_text):
        """Add text and save previous state for undo."""
        self.undo_stack.append(self.text)
        self.text += new_text
        self.redo_stack.clear()  # Clear redo stack when new action
    
    def undo(self):
        """Undo last action."""
        if self.undo_stack:
            self.redo_stack.append(self.text)
            self.text = self.undo_stack.pop()
            return True
        return False
    
    def redo(self):
        """Redo last undone action."""
        if self.redo_stack:
            self.undo_stack.append(self.text)
            self.text = self.redo_stack.pop()
            return True
        return False

# Usage
editor = TextEditor()
editor.type_text("Hello ")
editor.type_text("world!")
print(editor.text)  # "Hello world!"

editor.undo()
print(editor.text)  # "Hello "

editor.undo()
print(editor.text)  # ""

editor.redo()
print(editor.text)  # "Hello "

Performance Comparison

Operation List Deque Notes
append (right) O(1) O(1) Both efficient
appendleft O(n) O(1) Deque much better
pop (right) O(1) O(1) Both efficient
popleft O(n) O(1) Deque much better

Common Use Cases

Data Structure Use Cases
Stack Function calls, undo operations, browser back button
Queue Print jobs, task scheduling, breadth-first search
Deque Sliding windows, palindrome checking, recent items cache

Key Points to Remember

  • Stacks follow LIFO (Last In, First Out) principle
  • Queues follow FIFO (First In, First Out) principle
  • Deques provide efficient operations from both ends
  • Choose the right data structure based on your access patterns
  • Python's collections.deque is optimized for queue and stack operations
  • These fundamental structures power many real-world applications

Stacks and queues are linear data structures. In the next lesson, we'll explore trees - hierarchical structures that model many real-world relationships like family trees, file systems, and organizational charts.

© 2026 forEach. All rights reserved.

Privacy Policy•Terms of Service