Stacks and Queues#

Note

Source: Adapted from the C# edition (datastructures/datastructures.rst). C#’s Stack<T> and Queue<T> are replaced by Python’s list-based stack and collections.deque. The abstract data type concepts (LIFO, FIFO) are language-agnostic.

Stacks and queues are abstract data types — they define what operations are available, not how they are implemented.

Stacks (LIFO)#

A stack follows Last-In, First-Out order: the most recently added item is the first to be removed, like a stack of plates.

Operations:

  • push: add an item to the top

  • pop: remove and return the top item

  • peek: inspect the top item without removing it

  • is_empty: check whether the stack is empty

Using a Python list as a stack:

stack = []
stack.append(1)    # push
stack.append(2)
stack.append(3)

print(stack[-1])   # peek: 3
print(stack.pop()) # pop: 3
print(stack.pop()) # pop: 2
print(stack)       # [1]

list.append() adds to the end (top); list.pop() removes from the end — both O(1).

A Stack Class#

Wrapping the list in a class gives a cleaner interface:

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

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

    def pop(self):
        if self.is_empty():
            raise IndexError("pop from empty stack")
        return self._data.pop()

    def peek(self):
        if self.is_empty():
            raise IndexError("peek at empty stack")
        return self._data[-1]

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

    def __len__(self):
        return len(self._data)

Application: Checking Balanced Brackets#

A classic stack use-case: verify that brackets are correctly matched:

def is_balanced(s):
    stack = Stack()
    pairs = {")": "(", "]": "[", "}": "{"}
    for ch in s:
        if ch in "([{":
            stack.push(ch)
        elif ch in ")]}":
            if stack.is_empty() or stack.pop() != pairs[ch]:
                return False
    return stack.is_empty()
print(is_balanced("({[]})"))   # True
print(is_balanced("({[})"))    # False

Queues (FIFO)#

A queue follows First-In, First-Out order: like a line of people waiting, the first to join is the first to leave.

Operations:

  • enqueue: add an item to the back

  • dequeue: remove and return the front item

  • is_empty: check whether the queue is empty

Using ``collections.deque``:

A Python list is slow for dequeue (removing from the front is O(N)). collections.deque supports O(1) operations at both ends:

from collections import deque

queue = deque()
queue.append("Alice")    # enqueue
queue.append("Bob")
queue.append("Carol")

print(queue.popleft())   # dequeue: Alice
print(queue.popleft())   # dequeue: Bob
print(queue)             # deque(['Carol'])

A Queue Class#

from collections import deque

class Queue:
    def __init__(self):
        self._data = deque()

    def enqueue(self, item):
        self._data.append(item)

    def dequeue(self):
        if self.is_empty():
            raise IndexError("dequeue from empty queue")
        return self._data.popleft()

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

    def __len__(self):
        return len(self._data)