Picture the lunch queue at school. You join at the back; the person served next is always the one at the front — the person who has been waiting longest. Nobody (fairly!) barges in and gets served first. That single rule of fairness is exactly what a queue data structure captures: first in, first out, or FIFO.
A queue is a collection where you add at one end and remove from the other. Whatever went in first comes out first, so the order things arrive is the order they leave. It is one of the most useful structures in all of computing — and, like the queue you stand in, it is defined not by how it is stored but by the discipline it enforces on the order of arrivals and departures.
A queue exposes a small, fixed set of operations — and crucially it lets you touch only the two ends, never the middle:
x to the rear (the back of
the queue), where new arrivals join.Because you may only add at the rear and take from the front, the FIFO order is guaranteed by the structure itself — there is simply no operation that would let you jump the queue.
Below, items join at the rear on the right and leave from the front on the left. Step through it and notice the order in which values depart — it is exactly the order they arrived.
This is the whole idea in one picture: arrivals pile up at the back, departures peel off the front, and the queue quietly preserves arrival order from end to end.
The simplest way to build one is to wrap an array and only ever add to the back and remove from the
front. Here is a reusable Queue class. Watch the Output: the values
come out in the same order they went in —
Notice how dequeue always hands back the oldest waiting item. Swap the queue for
a stack and the last item in would come out first — the opposite order. That contrast is worth pinning
down.
A
Enqueue
Any time work must be handled fairly, in the order it arrived, there's a queue hiding underneath:
The array version above is easy to read, but shift() hides a cost: removing the front
element means every remaining item slides down one slot. Repeatedly enqueueing and dequeueing also
leaves a growing patch of "used up" space at the start of the array going to waste.
A circular queue fixes both. It keeps a fixed-size array and two indices —
front and rear — that wrap around to the start using the
remainder operator (% capacity) when they run off the end. Nothing ever slides; the
array is treated as a ring, so freed slots at the front are reused by later arrivals. Run it:
The visible order is still perfectly FIFO —
A queue has two different ends and it matters which is which — this is the classic trip-up. You enqueue at the rear (the back) and dequeue at the front (where items have waited longest). Mix them up and you have accidentally built a stack: adding and removing at the same end turns FIFO into LIFO and reverses your output order.
The second trap is queue underflow — calling dequeue() or
peek() on an empty queue. There is nothing to hand back, so a careful
implementation either returns a "nothing here" value (like undefined) or raises an
error — it must not crash or return junk. Always check isEmpty() first.
(Its cousin is overflow: enqueueing onto a full fixed-size queue, which
the circular queue above guards against by returning false.)
A neat memory aid: this is the exact opposite of a stack, end for end. A stack adds and removes at one end and reverses order; a queue uses opposite ends and preserves it.