Overview
A queue is a First-In-First-Out (FIFO) collection. Items are added at the back (enqueue) and removed from the front (dequeue). The oldest waiting item is always served next.
Queues model anything that waits its turn: tasks, requests, messages. In algorithms, the queue is the engine of breadth-first search, which explores nodes in order of distance and therefore finds shortest paths in unweighted graphs.
New customers join at the back and the cashier serves whoever is at the front. Nobody can skip ahead, so everyone is served in the order they arrived.
When to use it
- Items must be processed in arrival order.
- Breadth-first search, level-order traversal, shortest steps.
- Buffering between a producer and a consumer.
- Sliding time windows: count events in the last N seconds.
Problem patterns it solves
Recognize it when: minimum steps, nearest target, spreading from sources.
- 994. Rotting Oranges
- 1091. Shortest Path in Binary Matrix
- 752. Open the Lock
Recognize it when: process trees one level at a time.
- 102. Binary Tree Level Order Traversal
- 637. Average of Levels in Binary Tree
- 116. Populating Next Right Pointers
Recognize it when: count or keep events within the last T time units.
- 933. Number of Recent Calls
- 362. Design Hit Counter
- 346. Moving Average from Data Stream
Recognize it when: take turns, rotate, move the front to the back.
- 1823. Find the Winner of the Circular Game
- 2073. Time Needed to Buy Tickets
- 950. Reveal Cards In Increasing Order
- 1701. Average Waiting Time
Recognize it when: implement one structure using another.
- 232. Implement Queue using Stacks
- 225. Implement Stack using Queues
Where it is used in real software
RabbitMQ, Amazon SQS, and Kafka partitions deliver messages in order so producers and consumers can work at different speeds.
Incoming connections wait in an accept queue; thread pools pull tasks from a work queue.
Jobs are processed in submission order, often with priority queues layered on top.
Callbacks wait in the task queue and microtask queue and run in FIFO order when the call stack is empty.
Key terms
- enqueue / offer
- Add to the back. O(1).
- dequeue / poll
- Remove from the front. O(1) with a proper implementation.
- front / peek
- Read the front item without removing it.
- FIFO
- First in, first out.
- Head index
- An index into an array marking the logical front, avoiding O(n) shift.
Implementing a queue efficiently
- 1Avoid array.shift() in JavaScript
shift re-indexes every element, making each dequeue O(n).
- 2Use a head index
Store items in an array, keep head pointing at the front, and increment it on dequeue.
- 3Compact occasionally
When head passes half the array length, slice off consumed items to reclaim memory.
- 4In Java, use ArrayDeque
offer, poll, and peek are O(1). LinkedList also works but is slower.
- 5For fixed capacity, use a circular buffer
Wrap indexes with modulo so freed slots are reused.
Number of recent calls (window of 3000 ms)
ping(t) returns how many pings happened in [t - 3000, t]
| ping(t) | Enqueue | Dequeue (older than t - 3000) | Queue | Return |
|---|---|---|---|---|
| 1 | 1 | - | [1] | 1 |
| 100 | 100 | - | [1, 100] | 2 |
| 3001 | 3001 | - (1 >= 1) | [1, 100, 3001] | 3 |
| 3002 | 3002 | 1 (1 < 2) | [100, 3001, 3002] | 3 |
NOWping(t): 1 | Enqueue: 1 | Dequeue (older than t - 3000): - | Queue: [1] | Return: 1
Old timestamps leave from the front because they are the oldest. Each timestamp is enqueued and dequeued once, so the total work is O(n).
Implementation
class Queue { constructor() { this.items = []; this.head = 0; } enqueue(x) { this.items.push(x); } dequeue() { if (this.isEmpty()) return undefined; const x = this.items[this.head++]; if (this.head > 1024 && this.head * 2 > this.items.length) { this.items = this.items.slice(this.head); // reclaim memory occasionally this.head = 0; } return x; } peek() { return this.items[this.head]; } get size() { return this.items.length - this.head; } isEmpty() { return this.size === 0; }} class RecentCounter { constructor() { this.q = new Queue(); } ping(t) { this.q.enqueue(t); while (this.q.peek() < t - 3000) this.q.dequeue(); return this.q.size; }} // Queue from two stacks: amortized O(1)class MyQueue { constructor() { this.input = []; this.output = []; } push(x) { this.input.push(x); } #shift() { if (this.output.length === 0) { while (this.input.length) this.output.push(this.input.pop()); } } pop() { this.#shift(); return this.output.pop(); } peek() { this.#shift(); return this.output.at(-1); } empty() { return !this.input.length && !this.output.length; }}Complexity and performance
With a head index, circular buffer, or ArrayDeque.
Avoid it for large queues.
Each node is enqueued once.
Trade-offs
An unbounded queue can grow until memory runs out if producers are faster than consumers. Bounded queues apply backpressure by blocking or rejecting.
When some items are more urgent, a priority queue (heap) replaces the plain queue.
Variants and related techniques
Fixed-size ring buffer with O(1) operations and no reallocation.
Insert and remove at both ends.
Always removes the highest-priority item; implemented with a heap.
Consumers wait when empty and producers wait when full; Java's ArrayBlockingQueue.
Common mistakes
- Using shift() in JavaScript BFS on large graphs.
Fix: Use a head index or a real queue class.
- Using a queue when only the latest item matters.
Fix: That is a stack problem (LIFO).
- Reading queue.size inside the level loop.
Fix: Store the size before the loop; it changes as children are added.
Interview questions
Why does BFS use a queue?
FIFO order guarantees nodes are processed in order of their distance from the start, so the first time a node is reached is via a shortest path.
How do you implement a stack with queues?
On push, enqueue the new element and then rotate the queue by moving the previous size elements to the back, so the newest element is at the front. Push is O(n), pop is O(1).
Practice problems
| Problem | Difficulty | What it trains |
|---|---|---|
| 933. Number of Recent Calls | Easy | Time window queue. |
| 232. Implement Queue using Stacks | Easy | Amortized analysis. |
| 2073. Time Needed to Buy Tickets | Easy | Round-robin simulation. |
| 1823. Find the Winner of the Circular Game | Medium | Rotate and remove. |
| 102. Binary Tree Level Order Traversal | Medium | Level-by-level BFS. |
| 950. Reveal Cards In Increasing Order | Medium | Reverse simulation with a queue of indexes. |