3.2.7 · D5Linear Data Structures

Question bank — Queue — FIFO semantics, enqueue - dequeue, circular array implementation

1,646 words7 min readBack to topic

Before we start, one shared vocabulary so nothing below uses an unearned word:


True or false — justify

Every element eventually leaves a FIFO queue, no matter how many others arrive.
True — since removal is strictly in arrival order, an element only waits behind those who arrived earlier, a fixed finite set; no later arrival can jump ahead, so no starvation. Contrast a Priority Queue where a low-priority item can starve.
A circular queue with count can store N elements without any "wasted slot".
True — because count distinguishes empty (0) from full (N), all N slots are usable. The one-slot-sacrifice trick is only needed when you refuse to store a count.
In a circular queue, dequeuing physically moves the remaining elements to the front of the array.
False — nothing moves; only the front index advances (with ). Avoiding physical shifting is the entire reason the structure is O(1) per operation.
If front == rear, the queue is definitely empty.
False — with front/rear pointers alone, front == rear means either empty or full; the two states are indistinguishable, which is exactly why we store count.
After many enqueue/dequeue cycles, the front element can sit at a higher array index than the rear element.
True — once the queue wraps, e.g. front=2, rear=0, the elements are physically split across the seam yet logically contiguous. Physical scatter, logical order intact.
A queue and a stack differ only in the name of their operations.
False — they differ in which element leaves: a queue removes the oldest (FIFO), a stack removes the newest (LIFO). Swapping them turns a Breadth-First Search (BFS) into a depth-first search.
Increasing N changes the FIFO ordering of the elements already in the queue.
False — capacity only bounds how many can be held; the leave-order is fixed by arrival time regardless of N.
isFull and isEmpty can both be true at the same instant.
False — with the count scheme they are count==N and count==0; these can only coincide if N==0, a degenerate zero-capacity queue that holds nothing.
The modulo in (front + count) % N is only needed when the queue is full.
False — it is needed whenever front + count reaches or passes N, which can happen long before the queue is full (e.g. front=3, count=2, N=4 gives rear=1).

Spot the error

Code does front = front + 1 on dequeue, no modulo. What breaks and when?
When front reaches N it indexes one past the last slot → out-of-bounds (or reads garbage). The fix is front = (front + 1) % N so the front wraps back to 0.
A student uses rear = rear + 1 on enqueue and never wraps rear. Same bug?
Yes — rear marches off the right end and the queue reports "full" while left slots sit empty; that is the classic drift/waste trap the circular design exists to kill.
Someone tests full with front == rear while also keeping a count. Any problem?
The test is redundant and dangerous: front == rear is true for both empty and full, so it silently misclassifies states. Use count == N for full and count == 0 for empty and drop the pointer comparison.
enqueue writes arr[rear] = x but forgets count += 1. What happens next?
The element is stored but invisible: rear is recomputed from the stale count, so the very next enqueue overwrites x, and dequeue never returns it. The count is the queue's memory of size.
A dequeue sets arr[front] = None after reading but before advancing front, then advances. Bug?
No functional bug — clearing the slot is optional (it just drops the reference for garbage collection). The order is fine as long as you read the value before clearing.
Peek is implemented as return arr[rear]. Why is that wrong?
rear is the next free slot, not an element; peek must return arr[front], the element that will leave next. Reading rear returns stale or None data.

Why questions

Why store count instead of a rear index?
A lone rear index makes empty and full both look like front == rear; count is a single unambiguous number (0 vs N) that resolves the collision cleanly.
Why does rear = (front + count) % N correctly locate the next free slot?
The queue occupies count consecutive wrapping slots starting at front; the slot just past the last one is front + count, and folds that back into [0, N) when it overshoots.
Why is FIFO the right discipline for Breadth-First Search (BFS) but not for a stack-based DFS?
BFS must fully explore all nodes at the current distance before going deeper, and FIFO serves them in the exact order discovered; a stack (LIFO) would serve the newest first, diving deep instead of wide.
Why are all four core operations O(1) in the circular design?
Each op touches only the front/count numbers and one array slot — a fixed amount of work independent of how many elements are stored, since nothing is shifted.
Why does modular arithmetic, not an if index == N: index = 0 branch, feel like the "honest" tool here?
The wrap is fundamentally "position on a ring", which is precisely what computes; the if branch is just hand-coded, so the modulo states the intent directly and handles any overshoot uniformly. See Modular Arithmetic.
Why can a queue reject an enqueue even though the array still has physical space in some other scheme?
In the naïve non-wrapping array, "full" is tested by rear == N, which fires while the drifted-past left slots are empty; only wrapping (circular) reuses those slots.

Edge cases

Dequeue on an empty queue (count == 0) — what should happen?
It must raise/return an error (e.g. IndexError), never read arr[front], because that slot holds stale or None data and returning it would corrupt FIFO guarantees.
Enqueue on a full queue (count == N) — what should happen?
It must reject (raise OverflowError); otherwise rear would equal front and overwrite the oldest element, silently violating FIFO. A Circular Buffer / Ring Buffer sometimes chooses to overwrite, but a strict queue does not.
A queue of capacity N = 1: is the circular design still correct?
Yes — after one enqueue count=1=N (full); after dequeue count=0 (empty); rear = (front+1) % 1 = 0 always, and the single slot cycles correctly.
Capacity N = 0 (zero-length array) — what does the structure do?
It is permanently full and empty simultaneously in the sense that count can never exceed 0; every enqueue must fail immediately. It's a degenerate but consistent case worth guarding explicitly.
Front sits at N-1 and you dequeue — where does front land?
At (N-1 + 1) % N = 0, i.e. it wraps to the start of the array — the exact seam the circular design was built to cross seamlessly.
Enqueue exactly at the wrap seam: front=1, count=N-1, N — where does the new element go?
rear = (1 + (N-1)) % N = N % N = 0, so it lands at index 0, filling the queue to count = N and demonstrating the last free slot is behind the front.
If you enqueue and dequeue the same number of times forever, does the queue's used region drift or stay put?
It rotates around the ring endlessly without drifting off the end — front and rear both advance , so the structure never "runs out" of the array, which is the whole payoff over the naïve version.

Recall One-sentence summary of every trap here

Almost every mistake is one of three things: forgetting a % N, using front == rear as a full/empty test, or confusing the next free slot (rear) with a stored element (front).

Related deep structures to compare against: Deque — Double-Ended Queue, Priority Queue, Amortized Analysis (for growable variants).