C Programming Data Structures Queue And Circular Queue Complete Guide

 Last Update:2025-06-23T00:00:00     .NET School AI Teacher - SELECT ANY TEXT TO EXPLANATION.    8 mins read      Difficulty-Level: beginner

Understanding the Core Concepts of C Programming data structures Queue and Circular Queue


Data Structures: Queue and Circular Queue in C Programming

Queue: A linear data structure (DS) that follows the First In, First Out (FIFO) principle. This implies that elements are added at one end, known as the back or rear, and removed from the other end, known as the front.

Circular Queue: An advanced version of a queue where the last position is connected back to the first position to form a circle. This data structure overcomes the limitation of regular queues by utilizing space more efficiently.

Structure of a Queue

  • Front: Points to the element that will be dequeued first.
  • Rear: Points to the element that was recently enqueued.
  • Enqueue Operation: Adding an element to the rear.
  • Dequeue Operation: Removing an element from the front.

Basic Operations in a Queue

  1. Initialize Queue: Set front and rear to -1.
  2. Enqueue: Check if the queue is full (if (rear + 1) % SIZE == front). If not, increment rear and insert the element.
  3. Dequeue: Check if the queue is empty (if front == -1). If not, increment front and remove the element.
  4. Peek: Retrieve the value at the front of the queue without removing it.
  5. IsEmpty: Check if the queue has no elements.
  6. IsFull: Check if the queue cannot accept any more elements.

Queue Implementation in C Using an array, a queue can be implemented as follows:

#include <stdio.h>
#define SIZE 10

void initialize(int* front, int* rear) {
    *front = *rear = -1;
}

int isFull(int rear) {
    return (rear + 1) % SIZE == front;
}

int isEmpty(int front) {
    return front == -1;
}

void enqueue(int queue[], int* rear, int* front, int item) {
    if(isFull(*rear)) {
        printf("Queue Overflow\n");
        return;
    }
    if(isEmpty(*front))
        *front = 0;
    *rear = (*rear + 1) % SIZE;
    queue[*rear] = item;
}

int dequeue(int queue[], int* front, int* rear) {
    int item;
    if(isEmpty(*front)) {
        printf("Queue Underflow\n");
        return -1;
    }
    item = queue[*front];
    if(*front == *rear)
        *front = *rear = -1; // Reset queue to initial state
    else
        *front = (*front + 1) % SIZE;
    return item;
}

void peek(int queue[], int front) {
    if(isEmpty(front)) {
        printf("Queue Empty\n");
    } else {
        printf("%d\n", queue[front]);
    }
}

Advantages

  • Simple and efficient.
  • Used in scenarios like breadth-first search.
  • Ideal for operations requiring ordering of elements.

Disadvantages

  • Fixed size due to array implementation.
  • Waste of space when deque operations occur frequently.
  • Dequeue operation requires shifting elements.

Structure of a Circular Queue

A circular queue avoids the issue of wasted space by forming a logical loop between the rear and front of the queue. This makes the use of space more efficient and prevents the requirement of shifting elements during deque operations.

Basic Operations in a Circular Queue Circular Queue operations include all standard queue operations with additional circular behavior rules:

  1. Initialize Circular Queue: Similar to Queue initialization.
  2. Enqueue: Add an element at rear, incrementing rear in a circular manner.
  3. Dequeue: Remove an element from front, and increment front circularly.
  4. Peek: Similar to Queue peek.
  5. IsEmpty: Similar to Queue isEmpty.
  6. IsFull: Checks (rear + 1) % SIZE == front.

Circular Queue in C Using an array to create a circular queue:

#include <stdio.h>
#define SIZE 10

struct CircularQueue {
    int items[SIZE];
    int front;
    int rear;
};

int isFull(struct CircularQueue* cq) {
    return ((cq->rear + 1) % SIZE == cq->front);
}

int isEmpty(struct CircularQueue* cq) {
    return (cq->front == -1);
}

void enqueue(struct CircularQueue* cq, int item) {
    if(isFull(cq)) {
        printf("Queue Overflow\n");
        return;
    }
    if(cq->front == -1)
        cq->front = 0;
    cq->rear = (cq->rear + 1) % SIZE;
    cq->items[cq->rear] = item;
    printf("Inserted -> %d\n", item);
}

int dequeue(struct CircularQueue* cq) {
    int item;
    if(isEmpty(cq)) {
        printf("Queue Underflow\n");
        return -1;
    }
    item = cq->items[cq->front];
    if(cq->front == cq->rear) { // Last remaining element
        cq->front = cq->rear = -1;
    } else {
        cq->front = (cq->front + 1) % SIZE;
    }
    printf("Deleted -> %d\n", item);
    return item;
}

void peek(struct CircularQueue* cq) {
    if(isEmpty(cq)) {
        printf("Queue Empty\n");
    } else {
        printf("\nFront item: %d\n", cq->items[cq->front]);
    }
}

int main() {
    struct CircularQueue cq;
    cq.front = cq.rear = -1;

    enqueue(&cq, 1);
    enqueue(&cq, 2);
    enqueue(&cq, 3);

    peek(&cq);

    dequeue(&cq);
    dequeue(&cq);
    dequeue(&cq);

    enqueue(&cq, 10);

    peek(&cq);
    return 0;
}

Advantages

  • Efficient space usage.
  • No need to shift elements during the dequeue process.
  • Operations are constant time, O(1).

Disadvantages

  • Complex compared to simple queue implementations using arrays or linked lists.
  • Fixed size.
  • Requires careful handling of indices to avoid overflow/underflow conditions.

Comparison

  • Queue: Linear and simpler, but may waste space as front moves up after dequeuing.
  • Circular Queue: Logical looping around the queue, saves space but is more complex.

Applications

Both queues and circular queues find applications in various fields such as:

  • Operating Systems: For managing queues of processes.
  • Networks: In scheduling packets for transmission.
  • Computer Hardware: Buffer management systems often use them.
  • Real-time Systems: To handle events by their arrival order.

In conclusion, while queues provide the fundamental FIFO behavior, circular queues offer enhanced memory usage capabilities essential for many dynamic applications.


Online Code run

🔔 Note: Select your programming language to check or run code at

💻 Run Code Compiler

Step-by-Step Guide: How to Implement C Programming data structures Queue and Circular Queue

Example 1: Implementing a Queue

A queue is a linear data structure that follows the First-In-First-Out (FIFO) principle. This means the first element added to the queue will be the first one to be removed.

Step-by-Step Implementation:

  1. Define the Queue Structure:

    • We need an array to store the elements.
    • Two integers, front and rear, to keep track of the positions of the front and rear elements in the queue.
  2. Initialize the Queue:

    • Set front and rear to -1.
  3. Enqueue Operation:

    • Add an element to the rear of the queue.
    • If it is the first element, set both front and rear to 0.
    • Otherwise, increment rear.
  4. Dequeue Operation:

    • Remove an element from the front of the queue.
    • If the front is the same as the rear, set both front and rear to -1 because the queue would be empty after this operation.
    • Otherwise, increment front.
  5. Check if Queue is Empty:

    • Simply check if front is -1.
  6. Check if Queue is Full:

    • Check if rear is one position behind front.
  7. Display Queue Elements:

    • Loop through the array starting from front to rear.

Here is the implementation:

#include <stdio.h>
#include <stdbool.h>

#define MAX 10

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

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

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

// Function to add an element to the queue
void enqueue(int value) {
    if (isFull()) {
        printf("Queue is Full!\n");
    } else if (isEmpty()) {
        front = rear = 0;
    } else {
        rear++;
    }
    queue[rear] = value;
    printf("%d Enqueued\n", value);
}

// Function to remove an element from the queue
void dequeue() {
    if (isEmpty()) {
        printf("Queue is Empty!\n");
    } else if (front == rear) {
        printf("%d Dequeued\n", queue[front]);
        front = rear = -1;
    } else {
        printf("%d Dequeued\n", queue[front]);
        front++;
    }
}

// Function to display the queue elements
void displayQueue() {
    if (isEmpty()) {
        printf("Queue is Empty!\n");
    } else {
        printf("Queue elements are: ");
        for (int i = front; i <= rear; i++) {
            printf("%d ", queue[i]);
        }
        printf("\n");
    }
}

int main() {
    int choice, value;

    while (1) {
        printf("\nQueue Operations:\n");
        printf("1. Enqueue\n");
        printf("2. Dequeue\n");
        printf("3. Display Queue\n");
        printf("4. Exit\n");
        printf("Enter your choice: ");
        scanf("%d", &choice);

        switch (choice) {
            case 1:
                printf("Enter the value to Enqueue: ");
                scanf("%d", &value);
                enqueue(value);
                break;
            case 2:
                dequeue();
                break;
            case 3:
                displayQueue();
                break;
            case 4:
                exit(0);
            default:
                printf("Invalid Choice! Try again.\n");
        }
    }

    return 0;
}

Explanation:

  • When the program starts, front and rear are initialized to -1, indicating that the queue is empty.
  • The enqueue function checks if the queue is full before adding a new value. It adjusts the front and rear indices appropriately.
  • The dequeue function checks if the queue is empty before removing a value. It handles the scenario where the last element is removed and resets front and rear.
  • The displayQueue function loops from front to rear and prints all the elements currently in the queue.

Example 2: Implementing a Circular Queue

A circular queue is a variation of the queue that is circular in nature, which means that the tail's next reference points back to the head, forming a circle.

Step-by-Step Implementation:

  1. Define the Circular Queue Structure:

    • Use an array to store the elements.
    • Maintain front and rear pointers.
    • Ensure that space at index 0 is always unused when the queue is full.
  2. Initialize the Circular Queue:

    • Set front and rear to 0.
  3. Enqueue Operation:

    • Add an element to the rear of the queue.
    • Use (rear + 1) % MAX to get the next position for the rear.
    • Check if the queue is full before adding an element.
  4. Dequeue Operation:

    • Remove an element from the front of the queue.
    • Use (front + 1) % MAX to get the next position for the front.
    • Check if the queue is empty before removing an element.
  5. Check if Circular Queue is Empty:

    • The queue is empty if front is equal to rear.
  6. Check if Circular Queue is Full:

    • The queue is full if (rear + 1) % MAX equals front.
  7. Display Queue Elements:

    • Loop through the array starting from front to rear.

Here is the implementation:

Top 10 Interview Questions & Answers on C Programming data structures Queue and Circular Queue

1. What is a Queue in Data Structures?

Answer: A queue is a linear data structure that follows the First In, First Out (FIFO) principle. This means that elements are added at the back (rear) and removed from the front. Common operations include enqueue (adding an element), dequeue (removing an element), and checking if the queue is empty or full.

2. How do you implement a Queue using Arrays in C?

Answer: To implement a queue using arrays in C, you typically define an array and two integers, front and rear, to keep track of the positions of the first and last elements in the queue. Here’s a simple implementation:

#include <stdio.h>
#define SIZE 10

int queue[SIZE], front = -1, rear = -1;

void enqueue(int value) {
    if(rear == SIZE - 1)
        printf("Queue Overflow\n");
    else {
        if(front == -1)
            front = 0;
        rear++;
        queue[rear] = value;
    }
}

void dequeue() {
    if(front == -1 || front > rear) {
        printf("Queue Underflow\n");
        return;
    } else {
        printf("\n Deleted Element : %d\n", queue[front]);
        front++; 
    }
}

int main() {
    enqueue(10);
    enqueue(20);
    dequeue();
    enqueue(30);
    return 0;
}

3. What are the advantages of using a Queue in C?

Answer: The advantages of using a queue in C include:

  • Order Preservation: Maintains the order of elements as they enter.
  • Efficient for FIFO operations: Dequeue and enqueue operations can be implemented in constant time, O(1).
  • Simplicity: Easy to understand and implement using arrays or linked lists.

4. What is a Circular Queue? How does it solve the problem of wasted space in a regular Queue?

Answer: A circular queue overcomes the drawbacks of the normal array-based queue by connecting the end of the queue back to the front, making it more space-efficient.

  • Problem with Regular Queue: The regular queue implementation leads to "wasted space" once the rear reaches the maximum index of the array, even though the front has space before it.
  • Circular Queue Solution: The circular queue reuses the space of the array. When rear reaches the last element, the next element is placed at index 0 (if the front isn’t at index 0).

5. How do you implement a Circular Queue using Arrays in C?

Answer: Implementing a circular queue using arrays involves similar logic but includes modulo operation for wrapping around.

#include <stdio.h>
#define SIZE 10

int queue[SIZE], front = -1, rear = -1;

int isFull() {
    if((front == rear + 1) || (front == 0 && rear == SIZE - 1))
        return 1;
    return 0;
}

int isEmpty() {
    if(front == -1)
        return 1;
    return 0;
}

void enqueue(int element) {
    if(isFull())
        printf("Queue is full\n");
    else {
        if(front == -1) front = 0;
        rear = (rear + 1) % SIZE;
        queue[rear] = element;
    }
}

void dequeue() {
    if(isEmpty())
        printf("\nQueue is empty\n");
    else {
        printf("\nDeleted Element : %d\n", queue[front]);
        if(front == rear) {
            front = -1;
            rear = -1;
        } else {
            front = (front + 1) % SIZE;
        }
    }
}

int main() {
    enqueue(10);
    enqueue(20);
    dequeue();
    enqueue(30);
    return 0;
}

6. Can you explain the difference between a Queue and a Circular Queue?

Answer: While both queues and circular queues adhere to the FIFO principle:

  • Queue: Uses a linear array, where once elements are removed, no elements can be added until spaces are freed up from the front. This results in space wastage when front is not equal to 0 but rear reaches the end of the array.
  • Circular Queue: Reuses the space of the array to prevent wastage. The insertion happens at the start when the rear becomes equal to the array size.

7. What are the operations supported by a Circular Queue?

Answer: Operations supported by a circular queue in C include:

  • Enqueue: Adding an element to the rear of the queue.
  • Dequeue: Removing an element from the front of the queue.
  • IsFull: Checking whether the queue is full.
  • IsEmpty: Checking whether the queue is empty.
  • Peek/Front: Accessing the front element without removing it.
  • Size: Calculating the number of elements in the queue.

8. How do you handle overflow and underflow in a Circular Queue?

Answer: In a circular queue:

  • Overflow: Occurs when (rear + 1) % SIZE == front. Use the isFull() function to check for overflow.
  • Underflow: Happens when front == -1. Use the isEmpty() function to check for underflow.

9. Can you provide an example of a Circular Queue Application?

Answer: Applications of circular queues include:

  • CPU scheduling: For processes waiting to access CPU resources.
  • Memory Management: For memory buffers and input/output buffers.
  • Real-time systems: Where tasks must be handled in the order they arrive.
  • Traffic lights: Managing the queue of waiting cars efficiently.

10. How do you implement a Queue using Linked Lists in C?

Answer: Using linked lists, the queue has no upper limit based on system memory. Each node points to the next, avoiding the limitation of fixed-size arrays.

You May Like This Related .NET Topic

Login to post a comment.