Skip to content

Queue#

A queue is a FIFO (first-in, first-out) structure: enqueue at the rear, dequeue from the front. Classic uses include BFS, level-order traversal, task scheduling, and buffering.

When to use a queue#

Scenario Why queue
BFS on graph/grid Process nodes in increasing distance order
Level-order tree traversal Visit level k before level k+1
Sliding window maximum (with deque) See Deque
Producer–consumer / task pipeline Fair ordering

Do not use a Python list with pop(0) for BFS — each dequeue is O(n) because elements shift left.

Complexity#

Operation collections.deque List (pop(0)) Linked-list queue
Enqueue O(1) O(1) append O(1)
Dequeue O(1) O(n) O(1)
Peek front O(1) O(1) O(1)
Search O(n) O(n) O(n)
Space O(n) O(n) O(n)

Always prefer collections.deque in Python interviews.

Queue FIFO enqueue at rear and dequeue at front

from collections import deque

q: deque[int] = deque()

q.append(10)          # enqueue rear — O(1)
q.append(20)
front = q[0]          # peek — O(1)
x = q.popleft()       # dequeue front — O(1)

if q:
    q.popleft()

# BFS template
def bfs(start):
    queue = deque([start])
    visited = {start}
    while queue:
        node = queue.popleft()
        for neighbor in graph[node]:
            if neighbor not in visited:
                visited.add(neighbor)
                queue.append(neighbor)

Time: each node/edge processed once → O(V + E) for graphs.
Space: O(V) for queue + visited set.

Implementation with linked list#

Maintains O(1) enqueue and dequeue without shifting.

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

class QueueLinkedList:
    def __init__(self):
        self.front = None
        self.rear = None
        self._size = 0

    def enqueue(self, item) -> None:
        node = Node(item)
        if self.rear is None:
            self.front = self.rear = node
        else:
            self.rear.next = node
            self.rear = node
        self._size += 1

    def dequeue(self):
        if self.is_empty():
            raise IndexError("dequeue from empty queue")
        data = self.front.data
        self.front = self.front.next
        if self.front is None:
            self.rear = None
        self._size -= 1
        return data

    def peek(self):
        if self.is_empty():
            raise IndexError("queue is empty")
        return self.front.data

    def is_empty(self) -> bool:
        return self.front is None

    def size(self) -> int:
        return self._size

Time: enqueue/dequeue O(1).
Space: O(n) nodes.

Implementation with list (educational only)#

class QueueList:
    """Avoid in production — dequeue is O(n). Use collections.deque instead."""

    def __init__(self):
        self._items: list = []

    def enqueue(self, item) -> None:
        self._items.append(item)      # O(1)

    def dequeue(self):
        if self.is_empty():
            raise IndexError("dequeue from empty queue")
        return self._items.pop(0)     # O(n) — shifts all elements

    def peek(self):
        if self.is_empty():
            raise IndexError("queue is empty")
        return self._items[0]

    def is_empty(self) -> bool:
        return len(self._items) == 0

    def size(self) -> int:
        return len(self._items)

Queue vs stack vs deque#

Structure Order Primary ops Typical algorithm
Stack LIFO push/pop one end DFS, parsing, monotonic stack
Queue FIFO enqueue rear, dequeue front BFS, level order
Deque Both ends append/pop left & right BFS with 0-1 weights, sliding window

Circular queue (fixed capacity)#

Useful when buffer size is bounded (embedded systems, ring buffers):

class CircularQueue:
    def __init__(self, capacity: int):
        self.capacity = capacity
        self.buffer = [None] * capacity
        self.head = 0
        self.tail = 0
        self.count = 0

    def enqueue(self, item) -> bool:
        if self.count == self.capacity:
            return False
        self.buffer[self.tail] = item
        self.tail = (self.tail + 1) % self.capacity
        self.count += 1
        return True

    def dequeue(self):
        if self.count == 0:
            raise IndexError("empty queue")
        item = self.buffer[self.head]
        self.head = (self.head + 1) % self.capacity
        self.count -= 1
        return item

Time: O(1) enqueue/dequeue.
Space: O(capacity).

  • Deque — double-ended queue; BFS with deque
  • Graph — BFS traversal
  • Tree — level-order traversal
  • Stack — LIFO counterpart