Queue using array

An array-based queue stores elements in contiguous memory and tracks two indices: front (next to remove) and rear (last inserted). The best practical fixed-size design is the circular queue, where indices wrap with modulo and both enqueue and dequeue are O(1).

On this page
  • Representation — array, front/rear, size, capacity
  • Operations — enqueue/dequeue/peek with wrap-around
  • Example in C — circular queue implementation
  • Trade-offs — fixed capacity vs linked list

1) Array representation

To avoid costly shifts, use circular indexing instead of moving all elements after every dequeue.

Typical fields for a circular array queue in C
ComponentRoleNotes
items[]Stores queue elements.Fixed length MAX.
frontIndex of next element to dequeue.Valid when queue not empty.
rearIndex of last inserted element.Updated on enqueue with wrap-around.
sizeCurrent number of elements.Empty when size == 0, full when size == MAX.

2) Mapping operations

Queue operations with circular indices
OperationArray stepsFailure case
enqueue(x)if not full: rear=(rear+1)%MAX, store x, size++.Overflow if full.
dequeue()if not empty: read items[front], front=(front+1)%MAX, size--.Underflow if empty.
peek()if not empty: return items[front].Underflow if empty.
isEmpty()size == 0.
isFull()size == MAX.

3) Example in C

#include <stdio.h>
#include <stdlib.h>

#define MAX 5  // Maximum size of the queue

int queue[MAX];
int front = -1;
int rear = -1;

// Function to check if the queue is full
int isFull() {
    return rear == MAX - 1;
}

// Function to check if the queue is empty
int isEmpty() {
    return front == -1 || front > rear;
}

// Function to add an element to the queue (Enqueue)
void enqueue(int value) {
    if (isFull()) {
        printf("Queue Overflow! Cannot insert %d\n", value);
        return;
    }

    if (front == -1) {
        front = 0;  // Set front to 0 when inserting first element
    }

    rear++;
    queue[rear] = value;
    printf("Enqueued: %d\n", value);
}

// Function to remove an element from the queue (Dequeue)
void dequeue() {
    if (isEmpty()) {
        printf("Queue Underflow! Queue is empty\n");
        return;
    }

    printf("Dequeued: %d\n", queue[front]);
    front++;

    // Reset queue if it becomes empty
    if (front > rear) {
        front = -1;
        rear = -1;
    }
}

// Function to get the front element without removing it
int peek() {
    if (isEmpty()) {
        printf("Queue is empty\n");
        return -1;
    }
    return queue[front];
}

// Function to display all elements in the queue
void display() {
    if (isEmpty()) {
        printf("Queue is empty\n");
        return;
    }

    printf("Queue elements: ");
    for (int i = front; i <= rear; i++) {
        printf("%d ", queue[i]);
    }
    printf("\n");
}

// Main function to test the queue
int main() {
    printf("=== Queue Implementation using Array ===\n");
    printf("Maximum size: %d\n\n", MAX);

    enqueue(10);
    enqueue(20);
    enqueue(30);
    enqueue(40);
    enqueue(50);

    display();

    printf("\nFront element: %d\n", peek());

    dequeue();
    dequeue();

    display();

    enqueue(60);  // This will show overflow (queue is full)

    printf("\nFront element after dequeue: %d\n", peek());

    return 0;
}

Execution Flow with Output Table

Step-by-step execution with queue state and output
Step Operation Action Front Index Rear Index Queue State (front → rear) Output Printed
1enqueue(10)Insert 1000[10]Enqueued: 10
2enqueue(20)Insert 2001[10, 20]Enqueued: 20
3enqueue(30)Insert 3002[10, 20, 30]Enqueued: 30
4enqueue(40)Insert 4003[10, 20, 30, 40]Enqueued: 40
5enqueue(50)Insert 5004[10, 20, 30, 40, 50]Enqueued: 50
6display()Show all04[10, 20, 30, 40, 50]Queue elements: 10 20 30 40 50
7peek()View front04[10, 20, 30, 40, 50]Front element: 10
8dequeue()Remove front (10)14[20, 30, 40, 50]Dequeued: 10
9dequeue()Remove front (20)24[30, 40, 50]Dequeued: 20
10display()Show all24[30, 40, 50]Queue elements: 30 40 50
11enqueue(60)Try insert24 (MAX-1)[30, 40, 50]Queue Overflow! Cannot insert 60
12peek()View front24[30, 40, 50]Front element after dequeue: 30

Queue State Visualization Table

Array index view after each operation
After Operation Index 0 Index 1 Index 2 Index 3 Index 4 Front → Rear
Initialemptyemptyemptyemptyemptyfront = -1, rear = -1
After enqueue(10)10emptyemptyemptyempty0 → 0
After enqueue(20)1020emptyemptyempty0 → 1
After enqueue(30)102030emptyempty0 → 2
After enqueue(40)10203040empty0 → 3
After enqueue(50)10203040500 → 4
After dequeue()10203040501 → 4
After dequeue()10203040502 → 4

Note: strikethrough indicates deleted/ignored positions (wasted space).

Key Observations Table

Important behavior of array queue in this run
ConceptValue/StatusExplanation
Maximum Size5Queue can hold max 5 elements.
After 5 enqueuesQueue FULLrear = 4 (MAX-1).
After 2 dequeuesfront = 2First 2 positions (0,1) become unusable.
isFull() after dequeuesTRUE (still)rear is still 4, so insertion fails.
Wasted space2 positionsIndex 0 and 1 are empty but cannot be reused.
Final queue content[30, 40, 50]Only 3 valid elements remain.

Limitation Summary Table

Why linear array queue causes overflow with free slots
ProblemCauseConsequence
Cannot insert 60rear = MAX-1 (4)Even though front = 2 (space exists at 0,1).
Wasted memoryDeleted elements leave empty spacesMemory inefficient for dynamic workloads.
False OverflowisFull() checks only rear positionQueue reports FULL when actual elements < MAX.
SolutionUse Circular QueueReuses empty spaces by wrapping rear to 0.

4) Trade-offs

  • Pros — Simple, cache-friendly, O(1) operations with circular indexing.
  • Cons — Fixed capacity unless resized manually.

Compare with Queue using linked list for dynamic growth, and Circular queue for deeper wrap-around discussion.

Key takeaway

Use a circular array queue to keep enqueue/dequeue O(1) without element shifting. Track front, rear, and size consistently.

Next up: Queue using dynamic array · Queue using linked list · Circular queue