Back to Data Structures & Algorithms
2026-03-147 min read

Circular Queue Data Structure (Data Structures & Algorithms)

Learn Circular Queue Data Structure (Data Structures & Algorithms) step by step with clear examples and exercises.

Why This Matters

Circular Queues play a significant role in computer science, especially in applications that require fixed-sized buffers such as network communication, digital signal processing, and operating systems. They offer several benefits over traditional linear queues, including efficient memory utilization, reduced overhead, and simpler implementation. Understanding circular queues can help you tackle real-world programming problems, prepare for interviews focused on data structures and algorithms, and optimize the performance of your applications.

Prerequisites

Before diving into the core concept, it's important to have a solid understanding of Python basics:

  1. Variables and data types
  2. Control flow (if/else statements, loops)
  3. List manipulation
  4. Functions and modules
  5. Understanding basic concepts of data structures like linear queues and stacks
  6. Familiarity with common Python libraries such as collections.deque

Additionally, having knowledge about modulo arithmetic will be helpful in understanding the circular queue's behavior.

Core Concept

A circular queue is a type of linear data structure that uses a single, fixed-size buffer in memory, connected end-to-end to simulate an infinite buffer. It has two pointers: the front, which points to the first element, and the rear, which points to the next available position to insert an element. The rear pointer always moves ahead of the front pointer, wrapping around to the beginning when it reaches the end.

Here's a simple Python implementation of a circular queue using lists:

class CircularQueue:
def __init__(self, k):
self.k = k
self.queue = [None] * k
self.front = 0
self.rear = -1

Add an element to the queue

def enqueue(self, data):

if (self.rear + 1) % self.k == self.front:

print("Circular Queue is full")

else:

self.rear = (self.rear + 1) % self.k

self.queue[self.rear] = data

Remove an element from the queue

def dequeue(self):

if self.isEmpty():

print("Circular Queue is empty")

return None

else:

data = self.queue[self.front]

self.front = (self.front + 1) % self.k

return data

Check if the queue is empty

def isEmpty(self):

return self.rear == -1


### Using Collections.deque for Circular Queue

Python's built-in `collections.deque` can also be used to create a circular queue, with the advantage of faster appending and popping operations due to amortized constant time complexity:

from collections import deque

def make_circular_queue(k):

return deque([None] * k, maxlen=k)

Worked Example

Let's create a circular queue with a size of 5 and insert elements one by one using the CircularQueue class:

cq = CircularQueue(5)
cq.enqueue(1)
cq.enqueue(2)
cq.enqueue(3)
cq.enqueue(4)
cq.enqueue(5)
print("Circular Queue:", cq.queue)

Output:

Circular Queue: deque([1, 2, 3, 4, 5], maxlen=5)

Now let's remove elements from the queue using the dequeue() method:

print(cq.dequeue())
print(cq.dequeue())
print(cq.dequeue())
print("Circular Queue:", cq.queue)

Output:

1
2
3
Circular Queue: deque([4, 5], maxlen=5)

Using collections.deque, the same example can be written as follows:

cq = make_circular_queue(5)
cq.append(1)
cq.append(2)
cq.append(3)
cq.append(4)
cq.append(5)
print("Circular Queue:", cq)

Output:

Circular Queue: deque([1, 2, 3, 4, 5], maxlen=5)

Removing elements using pop() method:

print(cq.popleft())
print(cq.popleft())
print(cq.popleft())
print("Circular Queue:", cq)

Output:

1
2
3
Circular Queue: deque([4, 5], maxlen=5)

Common Mistakes

  1. Ignoring the wrap-around behavior: When adding or removing elements, remember that the pointers will wrap around to the beginning or end of the buffer when they reach the limit. This can lead to unexpected results if not handled correctly.
  1. Not handling the case when the queue is empty or full: Always check if the queue is empty before dequeuing and if it's full before enqueuing. This helps prevent errors and ensures that your code behaves predictably in all scenarios.
  1. Incorrectly implementing the circular queue: Make sure to implement the circular queue using a single, fixed-size buffer and use modulo arithmetic (%) for pointer manipulation. Avoid using multiple lists or arrays to simulate a circular queue.
  1. Using inefficient operations: Be aware that some Python list methods like append() and pop() have O(n) time complexity in the average case, while collections.deque offers faster appending and popping with amortized constant time complexity.
  1. Not properly handling overflow or underflow: If you want to allow the buffer to overflow or underflow, implement special cases for this behavior to avoid errors or unexpected results.

Practice Questions

  1. Implement a circular queue using Python lists and add/remove elements until it's full. Then, try to enqueue more elements and observe the behavior.
  2. Write a function that checks if a given list can be used as a circular queue with a specified size.
  3. Modify the CircularQueue class to allow peeking at the front element without removing it from the queue.
  4. Implement a circular queue using Python's collections.deque and compare its performance with the custom implementation in terms of time complexity and memory usage.
  5. Write a function that merges two circular queues into one, maintaining the order of elements and preserving the fixed size of each buffer.
  6. Implement a circular queue using Python's array module for better performance when dealing with large data sets.
  7. Implement a method to check if a given element is present in the circular queue without removing it.
  8. Write a function that finds the maximum and minimum elements in a circular queue.
  9. Modify the CircularQueue class to allow dynamic resizing of the buffer based on user input or runtime conditions.
  10. Implement a circular queue using Python's heapq module for priority-based operations.

FAQ

  1. What is the advantage of using a circular queue over a traditional linear queue? Circular queues offer better memory utilization since they can reuse buffer space when the rear pointer wraps around to the beginning. This is particularly useful in applications where fixed-size buffers are required, such as network communication or digital signal processing.
  1. How do I determine the size of a circular queue in Python? The size of a circular queue is typically defined as a constant at the time of initialization and can be accessed through the self.k attribute in the CircularQueue class. When using collections.deque, the maximum length (maxlen) can be set during instantiation or retrieved using the maxlen property.
  1. What happens when I try to enqueue an element into a full circular queue? If you attempt to enqueue an element into a full circular queue, the operation will fail, and an error message should be displayed. In some cases, it may be desirable to implement a solution that overflows the buffer by dropping older elements when it becomes full, but this is not typically recommended for efficient memory management.
  1. What is the time complexity of common operations in circular queues? The time complexity of common operations in a circular queue implemented using Python lists or arrays is as follows:
  • Enqueue: O(1) average case, O(n) in the worst case (when the buffer is full and elements need to be shifted)
  • Dequeue: O(1) average case, O(n) in the worst case (when the buffer is empty and elements need to be shifted)
  • Peek: O(1) if implemented correctly
  • Check if empty or full: O(1)
  1. What are some common applications of circular queues? Circular queues are commonly used in network communication, digital signal processing, operating systems, and embedded systems for efficient management of fixed-size buffers. They can also be found in real-time systems, audio processing software, and video game development.
  1. How does a circular queue handle the case when both front and rear pointers meet (collision) after inserting an element? In the event of a collision (when both the front and rear pointers meet), the rear pointer wraps around to the beginning of the buffer, overwriting the element at that position. This is known as circular queue's wrap-around behavior.
  1. What is the difference between a linear queue and a circular queue? A linear queue has a fixed size and uses two pointers: one for the front of the queue and another for the rear. When the rear reaches the end, it stops adding elements. In contrast, a circular queue also has a fixed size but wraps around when the rear pointer reaches the end, allowing it to continue adding elements.
  1. Can I implement a priority-based circular queue using Python's heapq module? Yes, you can create a priority-based circular queue by implementing a custom class that extends the circular queue concept and uses heapq for maintaining the priority of elements. This allows you to handle operations like finding the minimum or maximum element in constant time while still benefiting from circular queue's memory efficiency.
Circular Queue Data Structure (Data Structures & Algorithms) | Data Structures & Algorithms | XQA Learn