Implementing a queue using a linked list in C++

Implementing a Queue Using a Linked List in C++

Queues are fundamental data structures used in various applications, such as managing tasks in operating systems, handling requests in web servers, and implementing breadth-first search algorithms. In C++, a queue can be efficiently implemented using a linked list, which allows dynamic memory allocation and flexible sizing. This article will provide a comprehensive guide on implementing a queue using a linked list in C++, complete with code examples, use cases, and troubleshooting tips.

What is a Queue?

A queue is a linear data structure that follows the First In First Out (FIFO) principle, meaning that the first element added to the queue will be the first one to be removed. Imagine a line of people waiting at a ticket counter; the person who arrives first will be served first.

Key Operations of a Queue

The primary operations associated with a queue include:

  • Enqueue: Adding an element to the back of the queue.
  • Dequeue: Removing an element from the front of the queue.
  • Peek/Front: Retrieving the front element without removing it.
  • IsEmpty: Checking if the queue is empty.
  • Size: Returning the number of elements in the queue.

Why Use a Linked List for a Queue?

Using a linked list to implement a queue offers several advantages:

  • Dynamic Size: Unlike arrays, linked lists can grow and shrink dynamically.
  • Efficient Insertions and Deletions: Adding or removing elements from the front or back is done in constant time, O(1).
  • No Wasted Space: Linked lists use only as much memory as needed for the elements they hold.

Implementing a Queue Using a Linked List

Step 1: Define the Node Structure

The first step is to define a structure for the nodes of the linked list. Each node will contain a data field to store the queue element and a pointer to the next node.

struct Node {
    int data;      // Data field to store the value
    Node* next;    // Pointer to the next node

    Node(int val) : data(val), next(nullptr) {} // Constructor to initialize the node
};

Step 2: Create the Queue Class

Next, we will create the Queue class, which will manage the linked list and provide the necessary queue operations.

class Queue {
private:
    Node* front;  // Pointer to the front node
    Node* rear;   // Pointer to the rear node
    int size;     // To keep track of the number of elements

public:
    Queue() : front(nullptr), rear(nullptr), size(0) {} // Constructor to initialize the queue

    // Destructor to clean up the allocated memory
    ~Queue() {
        while (!isEmpty()) {
            dequeue();
        }
    }

    // Function to add an element to the queue
    void enqueue(int value) {
        Node* newNode = new Node(value); // Create a new node
        if (rear) {                      // If the queue is not empty
            rear->next = newNode;        // Link the new node at the end
        } else {
            front = newNode;             // If queue is empty, set front to new node
        }
        rear = newNode;                  // Set rear to the new node
        size++;                           // Increment the size
    }

    // Function to remove an element from the queue
    int dequeue() {
        if (isEmpty()) {
            throw std::out_of_range("Queue is empty!"); // Throw an error if the queue is empty
        }
        Node* temp = front;              // Store the front node
        int value = front->data;         // Get the data
        front = front->next;             // Move front to the next node
        if (!front) {                    // If the queue is now empty
            rear = nullptr;              // Set rear to nullptr
        }
        delete temp;                     // Delete the old front node
        size--;                           // Decrement the size
        return value;                    // Return the dequeued value
    }

    // Function to get the front element
    int peek() const {
        if (isEmpty()) {
            throw std::out_of_range("Queue is empty!"); // Throw an error if the queue is empty
        }
        return front->data;              // Return the front value
    }

    // Function to check if the queue is empty
    bool isEmpty() const {
        return size == 0;                // Return true if size is zero
    }

    // Function to get the size of the queue
    int getSize() const {
        return size;                     // Return the size of the queue
    }
};

Step 3: Testing the Queue Implementation

Now that we have implemented the queue using a linked list, let's test its functionality:

#include <iostream>

int main() {
    Queue q;

    // Enqueue elements
    q.enqueue(10);
    q.enqueue(20);
    q.enqueue(30);

    std::cout << "Front element: " << q.peek() << std::endl; // Should print 10
    std::cout << "Queue size: " << q.getSize() << std::endl; // Should print 3

    // Dequeue elements
    std::cout << "Dequeued: " << q.dequeue() << std::endl; // Should print 10
    std::cout << "Front element after dequeue: " << q.peek() << std::endl; // Should print 20
    std::cout << "Queue size: " << q.getSize() << std::endl; // Should print 2

    return 0;
}

Troubleshooting Common Issues

When implementing a queue using a linked list, you may encounter several common issues:

  • Memory Leaks: Ensure that you delete nodes when they are no longer needed, especially in the destructor.
  • Null Pointer Dereference: Always check if the queue is empty before calling dequeue or peek.
  • Incorrect Size Tracking: Make sure to increment and decrement the size variable appropriately in the enqueue and dequeue methods.

Conclusion

Implementing a queue using a linked list in C++ is a powerful way to utilize dynamic memory management and improve efficiency. With the steps outlined in this article, you can create a robust queue implementation that can be adapted for various use cases. Whether you are building a task scheduler or a breadth-first search algorithm, understanding how to implement and manage queues is a fundamental skill for any programmer. Happy coding!

SR
Syed
Rizwan

About the Author

Syed Rizwan is a Machine Learning Engineer with 5 years of experience in AI, IoT, and Industrial Automation.