Circular Queues in Data Structures

by Jasleen Chhabra | Updated on 24 August 2024

Queues are a fundamental data structure in computer science, used to manage collections of elements in a linear, first-in, first-out (FIFO) order. However, standard queues can sometimes be inefficient in their use of memory. This is where circular queues come into play, optimizing space usage by treating the queue as a circular buffer.

What is a Circular Queue?

A circular queue, also known as a ring buffer, is a type of queue in which the last position is connected back to the first position to make a circle. This connection allows the circular queue to efficiently utilize the available space by reusing the vacated spaces, thus overcoming the limitations of linear queues where space might be wasted if the front and rear pointers continue to move in one direction.

Key Features of Circular Queues

  1. Fixed Size: Circular queues have a fixed size, determined at the time of initialization.
  2. Circular Nature: The queue wraps around to the beginning when the end of the array is reached, making full use of the available space.
  3. Efficient Space Utilization: By reusing vacated spaces, circular queues ensure no memory is wasted.
  4. Two Pointers: Maintains two pointers, front and rear, to keep track of the positions for dequeuing and enqueuing operations.

Advantages of Circular Queues

  • Efficient Memory Usage: Circular queues make the most efficient use of memory by reusing spaces as soon as they are freed.
  • Performance: They offer constant-time complexity (O(1)) for insertion (enqueue) and deletion (dequeue) operations.
  • Useful in Real-Time Applications: Circular queues are widely used in buffering data streams, like handling keyboard input, streaming data, or managing tasks in an operating system.

Basic Operations in Circular Queues

  1. Enqueue Operation: Adds an element to the rear of the queue.
  2. Dequeue Operation: Removes an element from the front of the queue.
  3. Peek/Front Operation: Retrieves the front element without removing it.
  4. IsFull Operation: Checks if the queue is full.
  5. IsEmpty Operation: Checks if the queue is empty.

Implementation of Circular Queue

Let's look at how a circular queue can be implemented in C++.

#include <iostream>
#define MAX 5

class CircularQueue {
    int arr[MAX];
    int front, rear;

public:
    CircularQueue() : front(-1), rear(-1) {}

    bool isFull() {
        return (front == 0 && rear == MAX - 1) || (front == rear + 1);
    }

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

    void enqueue(int value) {
        if (isFull()) {
            std::cout << "Queue is Full" << std::endl;
            return;
        }

        if (front == -1) {
            front = 0;
        }

        rear = (rear + 1) % MAX;
        arr[rear] = value;
        std::cout << value << " added to the queue" << std::endl;
    }

    int dequeue() {
        if (isEmpty()) {
            std::cout << "Queue is Empty" << std::endl;
            return -1;
        }

        int value = arr[front];
        if (front == rear) {
            front = rear = -1;
        } else {
            front = (front + 1) % MAX;
        }
        std::cout << value << " removed from the queue" << std::endl;
        return value;
    }

    void displayQueue() {
        if (isEmpty()) {
            std::cout << "Queue is Empty" << std::endl;
            return;
        }

        int i = front;
        while (true) {
            std::cout << arr[i] << " ";
            if (i == rear) break;
            i = (i + 1) % MAX;
        }
        std::cout << std::endl;
    }
};

int main() {
    CircularQueue q;
    q.enqueue(10);
    q.enqueue(20);
    q.enqueue(30);
    q.enqueue(40);
    q.enqueue(50);
    q.displayQueue();
    q.dequeue();
    q.displayQueue();
    q.enqueue(60);
    q.displayQueue();

    return 0;
}

 

Practical Applications of Circular Queues

  1. CPU Scheduling: Used in round-robin scheduling algorithms.
  2. Memory Management: Circular buffers help manage data in streaming applications.
  3. Buffering Data: Used in IO buffering, network data handling, and multimedia applications.
  4. Handling Concurrency: Useful in scenarios requiring efficient and orderly handling of concurrent data, such as producer-consumer problems.

Conclusion

Circular queues offer an elegant solution to efficiently manage linear data structures within fixed memory limits. By reusing spaces and maintaining a circular structure, they optimize performance and memory utilization. Whether used in operating systems, data buffering, or real-time applications, understanding and implementing circular queues is essential for effective data management and system optimization.

FAQ

Any Questions?
Look Here.

Related Articles

Dequeue Operation in Queues

Enqueue Operation in Queues

Introduction to Queues