Queue (FIFO) Visualization — Step by Step

First In, First Out data structure. Enqueue adds to the rear, dequeue removes from the front.

Data StructuresbeginnerUpdated

// quick answer

Queue (FIFO) is a data structures structure that runs in O(1) time on average with O(n) space. First In, First Out data structure. Enqueue adds to the rear, dequeue removes from the front.

How Queue (FIFO) Works

A Queue is a linear data structure that follows FIFO (First In, First Out) ordering. Elements are added at the rear (enqueue) and removed from the front (dequeue). Common uses include BFS traversal, task scheduling, print queues, and message buffers. O(1) enqueue, dequeue, and peek.

Queue (FIFO) Step by Step

Two ends, one direction

A queue restricts access to *both* ends, each with a single job: elements enter at the rear and leave from the front. That is the FIFO invariant — First In, First Out — and it is exactly how a checkout line works: you join at the back, and the person who has waited longest is served first. Nothing can jump the line, and nothing can leave from the middle. Keeping a pointer to each end makes both operations O(1): enqueue writes at the rear pointer, dequeue reads at the front pointer, and neither ever scans the elements in between.

Enqueue and dequeue, traced

Start empty and enqueue(5), enqueue(2), enqueue(8). The queue reads [5, 2, 8] — 5 at the front, 8 at the rear. Now dequeue() returns 5, the first value in, leaving [2, 8]. Dequeue again and you get 2. Arrival order is preserved perfectly: elements exit in exactly the order they entered. peek() lets you inspect the front element without removing it, and dequeuing an empty queue is an underflow error. The visualizer demo runs the complete cycle — every value enqueued at the rear, then every value dequeued from the front — so you can watch FIFO play out step by step.

The naive array trap

The obvious implementation — a plain array where dequeue removes index 0 — hides an O(n) cost: removing the front forces every remaining element to shift left one slot (this is what JavaScript's Array.shift() does). For a queue processing millions of items, that turns each dequeue into a full-array copy. Two standard fixes exist. Keep a moving front index and simply advance it past dequeued slots, reclaiming space occasionally; or use a linked structure with head and tail pointers. Either way the goal is the same: dequeue must not move the elements that stay.

The circular buffer

The classic fixed-capacity solution is a circular buffer (ring buffer): an array of capacity k with front and rear indices that advance by (i + 1) % k, wrapping from the last slot back to slot 0. The array is treated as a ring, so slots freed at the front get reused by new arrivals at the rear — no shifting, no reallocation, ever. A count (or one deliberately empty slot) distinguishes full from empty, since both states have front == rear. Circular buffers back real systems everywhere: keyboard input buffers, audio streaming, network packet queues, and bounded producer–consumer channels.

Queues in the wild

Queues appear wherever fairness or arrival order matters. Breadth-first search is the flagship: a queue of frontier nodes guarantees vertices are visited level by level, which is precisely why BFS finds shortest paths in unweighted graphs — swap in a stack and the same code becomes DFS. Operating systems queue processes for CPU time, printers queue jobs, and web servers queue incoming requests. Message brokers like RabbitMQ and Kafka are, at heart, durable distributed queues that decouple producers from consumers so each side can run at its own pace.

Time & Space Complexity

Best CaseAverage CaseWorst CaseSpace
O(1)O(1)O(1)O(n)

Queue (FIFO) Pseudocode

Queue operations:
  enqueue(value):
    add value to rear
  dequeue():
    remove and return front
  peek():
    return front without removing

Press play in the visualizer above to watch each line execute with live highlighting.

Queue (FIFO)Code in JavaScript, Python & Java

JavaScript

class Queue {
  #items = [];
  #head = 0;

  enqueue(value) {
    this.#items.push(value);
  }

  dequeue() {
    if (this.isEmpty()) throw new Error('Queue underflow');
    const value = this.#items[this.#head++];
    // Reclaim space once half the array is dead slots
    if (this.#head * 2 >= this.#items.length) {
      this.#items = this.#items.slice(this.#head);
      this.#head = 0;
    }
    return value;
  }

  peek() {
    return this.#items[this.#head];
  }

  isEmpty() {
    return this.#head >= this.#items.length;
  }
}

Python

from collections import deque

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

    def enqueue(self, value):
        self._items.append(value)

    def dequeue(self):
        if self.is_empty():
            raise IndexError("queue underflow")
        return self._items.popleft()

    def peek(self):
        return self._items[0] if self._items else None

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

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

Java

import java.util.ArrayDeque;

public class Queue<T> {
    private final ArrayDeque<T> items = new ArrayDeque<>();

    public void enqueue(T value) {
        items.addLast(value);
    }

    public T dequeue() {
        if (isEmpty()) throw new IllegalStateException("Queue underflow");
        return items.removeFirst();
    }

    public T peek() {
        return items.peekFirst();
    }

    public boolean isEmpty() {
        return items.isEmpty();
    }

    public int size() {
        return items.size();
    }
}

When to Use Queue (FIFO)

  • Processing work in arrival order — web requests, print jobs, background tasks — where fairness matters and nothing should be starved.
  • BFS and anything level-by-level: shortest paths in unweighted graphs, spreading/flood-fill problems, computing degrees of separation.
  • Producer–consumer buffering between components running at different speeds: event loops, message brokers, streaming pipelines, rate limiters using a sliding window of timestamps.
  • When "most important first" matters more than "oldest first", you want a priority queue instead — typically a heap, which is a different structure with O(log n) operations.
  • Not the right tool for LIFO behavior (use a stack) or random access by index (use an array); a queue only ever exposes its front.
  • In JavaScript, avoid Array.shift() for large or hot queues — it is O(n) per dequeue. Use a head-index wrapper, a linked list, or a deque library; in Python reach for collections.deque.

Queue (FIFO) — Frequently Asked Questions

What is a queue used for in real life?

Anywhere first-come-first-served applies: print job queues, customer support ticket systems, web servers handling requests in arrival order, and operating systems scheduling processes. Message systems like RabbitMQ and Kafka are large-scale queues that let one part of a system hand work to another. In algorithms, breadth-first search relies on a queue to explore graphs level by level.

What is the difference between a queue and a stack?

A queue is FIFO — the oldest element leaves first, like a checkout line. A stack is LIFO — the newest element leaves first, like a stack of plates. A queue adds at one end and removes from the other; a stack does both at the same end. Swapping one for the other in graph traversal turns breadth-first search into depth-first search.

What is a circular queue and why use one?

A circular queue stores elements in a fixed-size array whose front and rear indices wrap around to the start using modulo arithmetic. When the front advances, its old slot becomes reusable by the rear, so no elements ever shift and no memory is reallocated. This gives guaranteed O(1) operations in constant space, which is why ring buffers appear in audio, networking, and embedded systems.

Why is dequeuing with Array.shift() slow in JavaScript?

Removing index 0 of an array forces every remaining element to move one position left, so each shift costs time proportional to the array length. Enqueue and dequeue a million items that way and you do roughly half a trillion element moves. Efficient queues avoid this with a moving front index, a linked list, or a circular buffer, keeping every operation O(1).

Is a priority queue the same as a queue?

No, despite the name. A regular queue serves elements in arrival order. A priority queue always serves the element with the highest (or lowest) priority regardless of when it arrived, and it is usually implemented as a binary heap rather than a linear queue. Its insert and remove operations cost O(log n) instead of the plain queue's O(1).

Compare Queue (FIFO)

Related Algorithms

References & Further Reading