Data Structures

Circular Queue Implementation using Linked List in C++

Linked List implementation can be the preferred choice for Circular Queue when the application uses dynamic data. This looks similar to Simple Queue, but additionally provides the ability to traverse the queue in circular fashion starting from any node.

See Circular Queue Implementation using Array to work with static data

1. Representation

Circular Queue Implementation using Linked List
Circular Queue Implementation using Linked List
/**
 * Queue Node Representation
 */
 struct Node {
     int element;
     Node* next;
 };

// Queue front pointer
Node* front = NULL;
    
// Queue rear pointer
Node* rear = NULL;

2. Circular Queue Implementation using Linked List

An example program to implement the Circular Queue using Linked List. This object-oriented implementation encapsulates the Queue data structure using a c++ class.

/**
 * C++ example to demonstrate Circular Queue implementation using Linked List
 */
#include <iostream>
using namespace std;

/**
 * Queue Node Representation
 */
 struct Node {
     int element;
     Node* next;
 };

/**
 * Circular Queue implementation using Linked List
 */
class CircularQueue
{
private:
    // Queue front pointer
    Node* front;
    
    // Queue rear pointer
    Node* rear;
    
public:
    // Constructor
    CircularQueue() : front(NULL), rear(NULL) {}
    
    // Enqueue new element to Queue
    void enqueue(int element);
    
    // Dequeue an element from Queue
    int dequeue();

    // Returns the top element without deleting
    int peek();
    
    // Print the Queue
    void display(string msg);
    
    // Check if the Queue is empty
    bool isEmpty();
};

// Enqueue new element to Queue
void CircularQueue::enqueue(int element) {		
    // Step 1. Create the new node
    Node* node = new Node();
    if (node == NULL) {
        cout << "System out of memory" << endl;
        return;
    }
    node->element = element;
	
    // Step 2. Connect the new node at Rear side
    if (rear == NULL) {
        // Step 2.A. If the Queue is empty, set the Front to point the new node.
        front = node;
    } else {
        // Step 2.B. Otherwise connect the new node after the Rear.
        rear->next = node;
    }
    
    // Step 3. Connect the new node to Front and form the circle
    node->next = front;
    
    // Step 4. Change the rear to point the new node
    rear = node;
}

// Dequeue an element from Queue
int CircularQueue::dequeue() {
    // Check if the Queue is empty
    if (front == NULL) {
        return -1;
    }
    
    // Step 1. Retrieve the element at Front
    int element = front->element;
	
    // Step 2. Remember the front node in a temporary pointer
    Node* tmp = front;
	
    // Step 3. Disconnect the front node
    if (front->next == NULL) {
        // Step 3.A. If the next node is not available, set Front and Rear to point the NULL
        front = rear = NULL;
    } else {
        // Step 3.B. Otherwise, change the Front to point the next node
        // and link the Rear to point the new Front node to form circle.
        front = front->next;
        rear->next = front;
    }
    
    // Step 4: Delete the node stored in temporary pointer
    delete tmp;
    
    return element;
}

// Returns the top element without deleting
int CircularQueue::peek() {
    if (isEmpty()) {
        return -1;
    }
    return front->element;
}

// Print the Queue
void CircularQueue::display(string msg) {
    cout << msg << endl;
    if (isEmpty()) {
        return;
    }
    
    if (front == rear) {
        cout << front->element << " <-- front, rear" << endl;
        
    } else {
        cout << front->element << " <-- front" << endl;
        for (Node* node=front->next; node != rear; node = node->next) {
            cout << node->element << endl;
        }
        cout << rear->element << " <-- rear";
    }
    
    if (rear->next == front) {
        cout << " (linked to front)" << endl;
    }
}

// Check if the Queue is empty
bool CircularQueue::isEmpty() {
    if (front == NULL) {
        cout << "Queue is Empty" << endl;
        return true;
    }
    return false;
}

// The main function to begin the execution
int main()
{
    // Create a Queue
    CircularQueue queue;
    
    // Push the elements (10, 20, 30, 40 and 50)
    queue.enqueue(10);
    queue.enqueue(20);
    queue.enqueue(30);
    queue.enqueue(40);
    queue.enqueue(50);
    queue.display("Queue after inserting 10 20 30 40 and 50");
    
    // Get the peek element
    int element = queue.peek();
    cout << "Peek element returned " << element << endl;
    
    // Pop the elements from Queue
    element = queue.dequeue();
    cout << "Dequeue element returned " << element << endl;
    element = queue.dequeue();
    cout << "Dequeue element returned " << element << endl;
    queue.display("Queue after removing two elements");
}
Output
Queue after inserting 10 20 30 40 and 50
10 <-- front
20
30
40
50 <-- rear (linked to front)
Peek element returned 10
Dequeue element returned 10
Dequeue element returned 20
Queue after removing two elements
30 <-- front
40
50 <-- rear (linked to front)

3. Operations of Circular Queue

Here, we discuss the operations performed on the Circular Queue with a Linked List.

3.1. Enqueue with Linked List

Enqueue operation inserts a new node on the rear side of the Circular Queue. Also, it connects the Rear with Front node to maintain the circular form.

Algorithm

  1. Create the new Node
  2. Connect the new node at Rear side with any one of the following steps.
    • 2.A. If the Queue is empty, set the Front to point the new node.
    • 2.B. Otherwise, connect the new node after the Rear.
  3. Connect the new node to Front and form the circle
  4. Update the Rear to point the new node

Examples

The queue is empty initially and the Front and Rear pointers are set to NULL value. Front and Rear points to be first node when inserted. Also, the first node has the link to itself to form the circle.

1. Initial Circular Queue
1. Initial Circular Queue
2. Enqueue the first element (10) to Circular Queue
2. Enqueue the first element (10) to Circular Queue

The Front and Rear pointers will be non NULL when the queue is not empty. The new element is inserted after the Rear node and the Rear pointer will be updated. Finally, the new node inserted at the Rear will be linked to Front node to form the circle.

3. After enqueue(20) to Circular Queue
3. After enqueue(20) to Circular Queue
4. After enqueue(30)
4. After enqueue(30)

3.2. Dequeue with Linked List

The dequeue operation removes an element from the Front side of the Queue.

Algorithm

  1. Check if the Queue is empty
  2. Retrieve the element at Front.
  3. Remember the front node in a temporary pointer.
  4. Disconnect the front node
    • 4.A. If the next node is not available, set Front and Rear to point the NULL
    • 4.B. Otherwise, change the Front to point the next node and link the Rear to point the new Front node.
  5. Delete the node referenced in the temporary pointer.

Examples

The queue must be non empty to perform the Dequeue operation. The element presents at the Front will be removed and the Front will point to the next node of the Queue. The Rear will now be pointing to the new Front node to retain the circular form.

1. Circular Queue before Dequeue
1. Circular Queue before Dequeue
2. Dequeue the first element (10)
2. Dequeue the first element (10)

The procedure differs a bit to dequeue the last element. The Front pointer can not be moved because the next node is unavailable. In such case, the Front and Rear will be set as NULL to indicate the queue is empty.

3. After Dequeue (20)
3. After Dequeue (20)
4. After Dequeue of last element (30)
4. After Dequeue of last element (30)
Copyright copyright 2024 Simplerize