Circular queue

A circular queue solves the wasted-space issue of a linear array queue by reusing freed positions via wrap-around indexing. Both enqueue and dequeue remain O(1).

On this page
  • Representation — array with front/rear pointers
  • Conditions — full and empty checks
  • Example in C — enqueue/dequeue with modulo
  • Trade-offs — fixed-size efficiency

1) Circular queue representation

Core fields in a circular queue
FieldPurposeRule
q[]Stores valuesFixed capacity MAX
frontNext index to dequeueAdvance by (front + 1) % MAX
rearLast inserted indexAdvance by (rear + 1) % MAX before insert
sizeCurrent element countEmpty if size == 0, full if size == MAX

2) Key operations and conditions

Circular queue operation mapping
OperationLogicFailure case
enqueue(x)check full, move rear circularly, assign, increment sizeOverflow if full
dequeue()check empty, read front, move front circularly, decrement sizeUnderflow if empty
peek()return q[front] without changing indicesUnderflow if empty

3) Example in C

#include <stdio.h>

#define MAX 5

static int q[MAX];
static int front = 0;
static int rear = -1;
static int size = 0;
static int queue_last;

int is_empty(void) { return size == 0; }
int is_full(void)  { return size == MAX; }

int enqueue(int value) {
    if (is_full()) return 0;
    rear = (rear + 1) % MAX;
    q[rear] = value;
    size++;
    return 1;
}

int dequeue(void) {
    if (is_empty()) return 0;
    queue_last = q[front];
    front = (front + 1) % MAX;
    size--;
    return 1;
}

int peek(void) {
    if (is_empty()) return 0;
    queue_last = q[front];
    return 1;
}

int main(void) {
    enqueue(10); enqueue(20); enqueue(30); enqueue(40);
    dequeue(); dequeue();      /* frees two positions */
    enqueue(50); enqueue(60);  /* wraps around */

    if (peek()) printf("peek: %d\n", queue_last);
    return 0;
}

Enqueue operation

Circular enqueue trace (MAX = 5)
Step Operation Value front (before) rear (before) size (before) Is full? Action (circular) rear (after) Queue array state size (after)
1enqueue(10)100-10Norear = (0) % 5 = 0, q[0]=100[10, ?, ?, ?, ?]1
2enqueue(20)20001Norear = (1) % 5 = 1, q[1]=201[10, 20, ?, ?, ?]2
3enqueue(30)30012Norear = (2) % 5 = 2, q[2]=302[10, 20, 30, ?, ?]3
4enqueue(40)40023Norear = (3) % 5 = 3, q[3]=403[10, 20, 30, 40, ?]4
5enqueue(50)50232Norear = (4) % 5 = 4, q[4]=504[?, 60, 30, 40, 50]3
6enqueue(60)60243Norear = (0) % 5 = 0, q[0]=600[60, 60, 30, 40, 50]4

Note: Steps 5–6 happen after dequeue operations (explained below).

Dequeue operation

Dequeue trace before wrap-around enqueues
Step Operation front (before) size (before) Queue array (before) Action queue_last set to front (after) size (after) Queue array (after)
1dequeue()04[10, 20, 30, 40, ?]queue_last = q[0]=10, front = (0+1)%5 = 11013[10, 20, 30, 40, ?]
2dequeue()13[10, 20, 30, 40, ?]queue_last = q[1]=20, front = (1+1)%5 = 22022[10, 20, 30, 40, ?]

Visual representation (circular queue)

After all operations:

Array indices:    0      1      2      3      4
Values:          [60,    20,    30,    40,    50]
                   ↑            ↑
                  rear         front
                 (points       (points
                  to 0)         to 2)

Key points

  • Circular wrap-around: rear goes from 4 to 0 (wrapped) when enqueuing 60.
  • FIFO behavior maintained: front always points to the next element to dequeue (30).
  • Efficient space usage: Reuses empty slots after dequeue.
  • Modulo arithmetic: (rear + 1) % MAX and (front + 1) % MAX enable circular behavior.

Final output

peek: 30

Execution summary

State flow
StepActionQueue order (front → rear)
1enqueue 10,20,30,40[10, 20, 30, 40]
2dequeue twice[30, 40]
3enqueue 50,60 (wrap-around)[30, 40, 50, 60]
4peekpeek: 30

4) Trade-offs

  • Pros — Reuses array slots, O(1) operations, memory predictable.
  • Cons — Capacity fixed; careful index logic required.

Use dynamic array queue when growth is needed, or linked-list queue for dynamic memory without resizing copies.

Key takeaway

Circular queue is the practical fixed-size array queue. Master wrap-around updates and full/empty checks to avoid index bugs.

Next up: Priority queue · Deque · Queue complexity