Algorithms in C#  

How to Implement a Circular Queue Using Arrays

Introduction

A Circular Queue is a linear data structure that follows the FIFO (First In, First Out) principle but connects the end of the queue back to the front, forming a circle. Unlike a regular queue, when the rear reaches the end of the array, it wraps around to the beginning (if space is available). This prevents wasted space and makes queue operations more efficient.

What Is a Circular Queue?

A Circular Queue is an enhanced version of a linear queue that efficiently utilizes space. In a linear queue, once the queue becomes full and elements are dequeued, the empty spaces at the beginning remain unused. The circular queue solves this problem by connecting the rear to the front.

Real-World Example

Think of a Ferris wheel — as each cabin goes off the top, it comes back around to the bottom for reuse. Similarly, in a circular queue, positions are reused when elements are removed.

Key Concepts

  • Front: Points to the first element in the queue.

  • Rear: Points to the last element in the queue.

  • MaxSize: The total capacity of the queue.

  • Wrap-around: When the rear moves to the start after reaching the end.

Important Conditions:

  • Queue is empty: front == -1

  • Queue is full: (rear + 1) % MaxSize == front

Steps to Implement a Circular Queue

1. Define the Queue Class

Create a class CircularQueue with required variables.

using System;

public class CircularQueue
{
    private int[] queue;
    private int front;
    private int rear;
    private int maxSize;

    public CircularQueue(int size)
    {
        queue = new int[size];
        maxSize = size;
        front = -1;
        rear = -1;
    }
}

2. Enqueue Operation (Insert Element)

public void Enqueue(int item)
{
    if ((rear + 1) % maxSize == front)
    {
        Console.WriteLine("Queue is full. Cannot insert.");
        return;
    }

    if (front == -1) // Queue is empty
        front = 0;

    rear = (rear + 1) % maxSize;
    queue[rear] = item;

    Console.WriteLine($"Inserted {item} into the queue.");
}

3. Dequeue Operation (Remove Element)

public int Dequeue()
{
    if (front == -1)
    {
        Console.WriteLine("Queue is empty. Nothing to dequeue.");
        return -1;
    }

    int item = queue[front];

    if (front == rear)
    {
        front = rear = -1; // Queue becomes empty
    }
    else
    {
        front = (front + 1) % maxSize;
    }

    Console.WriteLine($"Removed {item} from the queue.");
    return item;
}

4. Display Queue Elements

public void Display()
{
    if (front == -1)
    {
        Console.WriteLine("Queue is empty.");
        return;
    }

    Console.WriteLine("Queue elements are:");
    int i = front;
    while (true)
    {
        Console.Write(queue[i] + " ");
        if (i == rear)
            break;
        i = (i + 1) % maxSize;
    }
    Console.WriteLine();
}

5. Full Working Example

class Program
{
    static void Main()
    {
        CircularQueue cq = new CircularQueue(5);

        cq.Enqueue(10);
        cq.Enqueue(20);
        cq.Enqueue(30);
        cq.Enqueue(40);

        cq.Display();

        cq.Dequeue();
        cq.Display();

        cq.Enqueue(50);
        cq.Enqueue(60); // Wrap-around insertion

        cq.Display();
    }
}

Output:

Inserted 10 into the queue.
Inserted 20 into the queue.
Inserted 30 into the queue.
Inserted 40 into the queue.
Queue elements are:
10 20 30 40
Removed 10 from the queue.
Queue elements are:
20 30 40
Inserted 50 into the queue.
Inserted 60 into the queue.
Queue elements are:
20 30 40 50 60

Advantages of Circular Queue

  • Efficient use of memory — no wasted space.

  • Prevents overflow if elements are removed and space becomes available.

  • Simplifies resource scheduling tasks (like CPU scheduling or buffering).

Limitations

  • Fixed size — cannot dynamically grow.

  • Slightly complex logic for wrap-around.

Real-World Use Cases

  • CPU Scheduling (Round Robin Algorithm)

  • Memory Buffers (Circular Buffers)

  • Streaming Services (Handling Continuous Data)

Summary

A Circular Queue in C# efficiently utilizes space by connecting the end of the queue to the front, allowing elements to wrap around. Using simple arithmetic with modulo %, you can manage front and rear pointers effectively. By implementing operations like enqueue, dequeue, and display, you can manage data efficiently for scheduling, buffering, and real-time data applications.