Skip to study material
← Question index

QUESTION 18

Explain a circular array queue with full and empty conditions.

5 marks

Answer in brief

A circular queue reuses the front positions of a bounded array after earlier items are removed.

Representation

Keep an array, front index and count. The next insertion index is (front + count) % capacity. This convention avoids confusing full and empty states when front and rear indices happen to be equal. Other valid conventions may reserve a slot and use different conditions.

Enqueue

  1. Reject count == capacity.
  2. Store at (front + count) % capacity.
  3. Increment count.

Dequeue

  1. Reject count == 0.
  2. Save the item at front.
  3. Set front = (front + 1) % capacity and decrement count.
  4. Return success and the saved item.

Example

With capacity 3, enqueue 10, 20 and 30, then dequeue 10. Enqueue 40 uses the newly available wrapped position. Logical order is 20, 30, 40 even though physical index order has wrapped. Display from front for count elements, applying modulo.

Complexity and constraints

Each operation performs fixed work, giving O(1) time. The array uses O(capacity) storage. Capacity must be positive before modulo is used. Do not combine the full condition from a reserved-slot implementation with this count-based implementation without changing the rest of the design.

Complete C example

main.c

Download main.c
/* CodeBhavya | Data Structures AR25 | Learning example */
#include <stdio.h>
#define CAP 3
struct Queue { int data[CAP]; int front, count; };
int enqueue(struct Queue *q, int value)
{
    if (q->count == CAP) { return 0; }
    q->data[(q->front + q->count) % CAP] = value; ++q->count; return 1;
}
int dequeue(struct Queue *q, int *out)
{
    if (q->count == 0) { return 0; }
    *out = q->data[q->front]; q->front = (q->front + 1) % CAP; --q->count; return 1;
}

int main(void)
{
    struct Queue q = {{0}, 0, 0}; int value;
    if (!enqueue(&q, 10) || !enqueue(&q, 20) || !enqueue(&q, 30)) { return 1; }
    if (dequeue(&q, &value)) { printf("Removed = %d\n", value); }
    if (!enqueue(&q, 40)) { return 1; }
    while (dequeue(&q, &value)) { printf("%d\n", value); }
    return 0;
}

Sample input and output

The example uses values in the code.

Output

Removed = 10
20
30
40

Trace a full queue, a removal and a wrapped insertion

Use the count-based queue in the program, with capacity 3. In the table, “next slot” means (front + count) % 3. It is an insertion position only when the queue is not full.

↔ Scroll horizontally on a small screen
Circular queue state changes
OperationfrontcountNext slotLogical queue
Initial state000Empty
Enqueue 1001110
Enqueue 2002210, 20
Enqueue 30030 — full10, 20, 30
Try enqueue 99030 — fullRejected; still 10, 20, 30
Dequeue12020, 30
Enqueue 40131 — full20, 30, 40

After the final insertion, the physical array contains 40, 20, 30. Reading physical indexes 0, 1 and 2 would print the wrong queue order. Starting at front gives indexes 1, 2 and 0, so the correct order is 20, 30, 40.

Why the full check must come first

When count is 3, the formula points to the slot holding the oldest item. Writing 99 there before checking fullness would destroy an item that has not been removed. The enqueue function must reject the operation before changing either the array or count.

Empty queue case

After all three items are removed, count is zero. Front need not return to zero for the queue to be empty. Another dequeue must return failure, and the caller must not treat the output variable as a newly removed value. The operation does not shift array elements; it updates only an index and a count.