First In, First Out (FIFO)
CS205 Data Structures
Arrow keys or Space to navigate
A queue is a collection of elements with a First-In, First-Out (FIFO) access policy.
The first person who lines up is the first person served. New arrivals join the back of the line. Cutting is not allowed!
FIFO = the element that has been waiting the longest gets served first. Fair and orderly!
| Operation | Description | Time |
|---|---|---|
enqueue(e) | Insert element at rear | O(1) |
dequeue() | Remove & return front element | O(1) |
front() | Return front without removing | O(1) |
isEmpty() | Is the queue empty? | O(1) |
size() | Number of elements | O(1) |
All core queue operations are O(1) -- constant time, regardless of how many elements are stored.
Add a new element to the rear of the queue.
Enqueue always operates on the rear end. The front is untouched. This is O(1).
Remove and return the element at the front of the queue.
Calling dequeue() on an empty queue is an error. Always guard with isEmpty() or handle the exception.
Last In, First Out
Think: stack of plates. You take the top plate off first.
| Operation | Stack |
|---|---|
| Insert | push(e) |
| Remove | pop() |
| Peek | top() |
First In, First Out
Think: line at a store. The first person in line is served first.
| Operation | Queue |
|---|---|
| Insert | enqueue(e) |
| Remove | dequeue() |
| Peek | front() |
Stack and Queue are both restricted-access data structures. The difference is which end you remove from. Stack: same end as insert. Queue: opposite end from insert.
Store elements in an array. Enqueue at the end, dequeue from index 0.
Every dequeue() shifts all remaining elements one position to the left. For n elements, that is O(n) work per dequeue.
This is better, but we waste all the space before front. Solution: wrap around!
When the rear reaches the end of the array, it wraps around to index 0 using modulo arithmetic.
If N = 8 and rear = 7:
(7 + 1) % 8 = 0
The index wraps back to the beginning! The array is treated as a ring.
Trace operations on a circular array of capacity N = 5. Indices 0..4.
Both front and rear wrap around independently. The array is reused -- no wasted space, no shifting. Every enqueue and dequeue is O(1).
A tricky problem: when front == rear, is the queue empty or full?
If you use neither solution, you cannot distinguish full from empty. This is a classic bug in circular buffer implementations.
Use a singly linked list with both head and tail pointers.
We need head for O(1) dequeue (remove first node) and tail for O(1) enqueue (append at end). Without tail, enqueue would require traversing the entire list -- O(n)!
A generalization that allows insertion and removal at both ends.
| Operation | Description |
|---|---|
addFirst(e) | Insert at front |
addLast(e) | Insert at rear |
removeFirst() | Remove from front |
removeLast() | Remove from rear |
first() | Peek at front |
last() | Peek at rear |
A Deque subsumes both Stack and Queue:
Can be implemented with a doubly linked list or a circular array. Java provides ArrayDeque and LinkedList (both implement Deque).
A shared printer uses a queue to manage incoming print jobs fairly.
Just like a line at a deli counter: first come, first served. The printer does not skip anyone -- jobs are processed in the exact order they were submitted.
Any system that needs fair, ordered processing of requests is a natural fit for a queue: OS task scheduling, network packet buffers, message queues, etc.
A queue drives level-by-level traversal of a tree or graph.
BFS explores all neighbors at the current depth before moving deeper. The queue ensures this level-by-level ordering.
Players stand in a circle. A "hot potato" is passed k times, and the person holding it is eliminated. Last one standing wins.
Dequeue + re-enqueue simulates circular passing. After k passes, dequeue without re-enqueue = elimination.
What if not everyone should wait equally? What if some elements are more urgent?
A Priority Queue is NOT a queue. It does not follow FIFO. Instead, the element with the highest priority (often the minimum key) is removed first.
A regular queue is like a deli counter with numbered tickets. A priority queue is like an ER triage: the sickest patient goes first, even if they just walked in.
Coming up: heaps, the efficient way to implement priority queues!
Writing rear++ instead of rear = (rear + 1) % N. This causes an ArrayIndexOutOfBounds when rear exceeds the array length.
Always check isEmpty() before calling dequeue(). An empty dequeue is undefined behavior in some implementations, or throws an exception in others.
Enqueue at rear, dequeue from front. Mixing these up produces a stack-like structure or corrupted data.
In a circular array without a size counter, both full and empty states have front == rear. Always use a count variable or waste-one-slot strategy.
After dequeuing, set data[front] = null to avoid memory leaks (loitering references prevent garbage collection).
| Property | Value |
|---|---|
| Access Policy | FIFO |
| enqueue | O(1) |
| dequeue | O(1) |
| front / peek | O(1) |
| isEmpty / size | O(1) |
| Array (Circular) | Linked List | |
|---|---|---|
| enqueue | O(1) amortized | O(1) |
| dequeue | O(1) | O(1) |
| Memory | Compact, cache-friendly | Extra pointer overhead |
| Resize | O(n) when full | Never needed |