A circular queue is a linear data structure that operates in a circular fashion. Unlike a normal queue where the rear pointer moves only in one direction, in a circular queue, the rear pointer wraps around when it reaches the end of the array, making it circular. This helps in efficiently utilizing the memory space.
Program Explanation
The circular queue is implemented using an array with two pointers, front and rear:
- front: Points to the first element in the queue.
- rear: Points to the last element in the queue.
The circular nature is maintained by adjusting the front
and rear
pointers with modulo arithmetic to wrap around when they reach the end of the array.
C Program Code
#include <stdio.h>
#include <stdlib.h>
#define MAX 5 // Define the maximum size of the circular queue
// Circular Queue structure
struct CircularQueue {
int arr[MAX];
int front, rear;
};
// Initialize the circular queue
void initQueue(struct CircularQueue *q) {
q->front = -1;
q->rear = -1;
}
// Check if the queue is full
int isFull(struct CircularQueue *q) {
return ((q->rear + 1) % MAX == q->front);
}
// Check if the queue is empty
int isEmpty(struct CircularQueue *q) {
return (q->front == -1);
}
// Add an element to the circular queue
void enqueue(struct CircularQueue *q, int value) {
if (isFull(q)) {
printf("Queue is full. Cannot enqueue %d.\n", value);
return;
}
if (isEmpty(q)) {
q->front = 0;
}
q->rear = (q->rear + 1) % MAX;
q->arr[q->rear] = value;
printf("Enqueued %d\n", value);
}
// Remove an element from the circular queue
int dequeue(struct CircularQueue *q) {
if (isEmpty(q)) {
printf("Queue is empty. Cannot dequeue.\n");
return -1;
}
int dequeuedValue = q->arr[q->front];
if (q->front == q->rear) {
// The queue becomes empty after this operation
q->front = -1;
q->rear = -1;
} else {
q->front = (q->front + 1) % MAX;
}
printf("Dequeued %d\n", dequeuedValue);
return dequeuedValue;
}
// Display the elements of the circular queue
void displayQueue(struct CircularQueue *q) {
if (isEmpty(q)) {
printf("Queue is empty.\n");
return;
}
printf("Queue elements: ");
int i = q->front;
while (i != q->rear) {
printf("%d ", q->arr[i]);
i = (i + 1) % MAX;
}
printf("%d\n", q->arr[q->rear]); // Print the last element
}
// Main driver function
int main() {
struct CircularQueue q;
initQueue(&q);
enqueue(&q, 10); // Enqueue 10
enqueue(&q, 20); // Enqueue 20
enqueue(&q, 30); // Enqueue 30
enqueue(&q, 40); // Enqueue 40
enqueue(&q, 50); // Enqueue 50 (queue is full now)
displayQueue(&q); // Display the queue
dequeue(&q); // Dequeue an element
dequeue(&q); // Dequeue another element
displayQueue(&q); // Display the queue again
enqueue(&q, 60); // Enqueue 60 (wrap around occurs)
enqueue(&q, 70); // Enqueue 70 (queue is full again)
displayQueue(&q); // Display the queue after wrap around
return 0;
}
Code Explanation
1. Circular Queue Structure: The queue is represented as an array of fixed size (MAX
) and two pointers: front
and rear
. These pointers are used to keep track of the first and last elements of the queue.
2. Basic Queue Operations:
enqueue()
: Adds an element to the queue. If the queue is full (when(rear + 1) % MAX == front
), no more elements can be added. Therear
pointer is updated using modulo arithmetic to ensure circular movement.dequeue()
: Removes an element from the front of the queue. If the queue becomes empty after a dequeue operation, bothfront
andrear
are set to-1
.isFull()
andisEmpty()
: Check if the queue is full or empty, respectively.displayQueue()
: Displays the current elements in the queue fromfront
torear
.
Sample Output
Enqueued 10
Enqueued 20
Enqueued 30
Enqueued 40
Enqueued 50
Queue elements: 10 20 30 40 50
Dequeued 10
Dequeued 20
Queue elements: 30 40 50
Enqueued 60
Enqueued 70
Queue elements: 30 40 50 60 70
Conclusion
This program demonstrates the implementation of a circular queue in C using an array. The use of modulo arithmetic ensures that the queue behaves in a circular manner, allowing efficient use of space even after dequeuing elements. Circular queues are widely used in situations where buffer management is needed, such as in operating systems, network buffering, and real-time processing systems.