Table of contents

Introduction to Queue Data Structure

What is a Queue?

A queue is a linear data structure that follows the First In, First Out (FIFO) principle. This means that the first element added to the queue will be the first one to be removed. Queues are widely used in various applications, including scheduling processes in operating systems, handling requests in web servers, and managing tasks in print spooling.

Representation of a Queue Data Structure

plaintext

Initial State:
Front: |   |   |   |   |   | Rear

After Enqueueing Elements (Enqueue 1, Enqueue 2, Enqueue 3):
Front: | 1 | 2 | 3 |   |   | Rear

After Dequeueing an Element (Dequeue):
Front: |   | 2 | 3 |   |   | Rear

After Enqueueing Another Element (Enqueue 4):
Front: |   | 2 | 3 | 4 |   | Rear

Types of Queues

  1. Simple Queue: Also known as a linear queue, where insertion happens at the rear and deletion happens at the front.
  2. Circular Queue: The last position is connected back to the first position to make a circle. It overcomes the limitation of the simple queue.
  3. Priority Queue: Each element is assigned a priority, and elements are dequeued in order of their priority.
  4. Double-Ended Queue (Deque): Insertion and deletion can happen at both the front and rear ends.

Key Operations on Queues

  1. Enqueue: Adding an element to the rear of the queue.
    • Example: Enqueue 5 -> Queue: [5]
  2. Dequeue: Removing the front element from the queue.
    • Example: Dequeue -> Queue: []
  3. Front/Peek: Accessing the front element without removing it.
    • Example: Front -> 5
  4. isEmpty: Checking if the queue is empty.
    • Example: isEmpty() -> True if the queue is empty, False otherwise

Here are some basic implementations of a queue in C++, Java, and Python.

C++ Program to implement Queue

cpp
#include <iostream>
#include <queue>
using namespace std;

int main() {
    queue<int> q;

    // Enqueue elements to the queue
    q.push(1);
    q.push(2);
    q.push(3);
    cout << "Queue elements: ";
    queue<int> temp_q = q;
    while (!temp_q.empty()) {
        cout << temp_q.front() << " ";
        temp_q.pop();
    }
    cout << endl;

    // Peek the front element
    cout << "Front element: " << q.front() << endl;

    // Dequeue an element from the queue
    q.pop();
    cout << "After dequeueing, queue elements: ";
    temp_q = q;
    while (!temp_q.empty()) {
        cout << temp_q.front() << " ";
        temp_q.pop();
    }
    cout << endl;

    // Check if the queue is empty
    cout << "Is queue empty? " << (q.empty() ? "Yes" : "No") << endl;

    return 0;
}

Java Program to implement Queue

java
import java.util.LinkedList;
import java.util.Queue;

public class Main {
    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList<>();

        // Enqueue elements to the queue
        queue.add(1);
        queue.add(2);
        queue.add(3);
        System.out.println("Queue elements: " + queue);

        // Peek the front element
        System.out.println("Front element: " + queue.peek());

        // Dequeue an element from the queue
        queue.remove();
        System.out.println("After dequeueing, queue elements: " + queue);

        // Check if the queue is empty
        System.out.println("Is queue empty? " + (queue.isEmpty() ? "Yes" : "No"));
    }
}

Python Program to implement Queue

python
from collections import deque

class Queue:
    def __init__(self):
        self.elements = deque()

    def enqueue(self, x):
        self.elements.append(x)

    def dequeue(self):
        if not self.elements:
            print("Queue is empty!")
            return
        return self.elements.popleft()

    def front(self):
        if not self.elements:
            print("Queue is empty!")
            return None
        return self.elements[0]

    def is_empty(self):
        return len(self.elements) == 0

    def print_queue(self):
        print(" ".join(map(str, self.elements)))

# Main function
if __name__ == "__main__":
    queue = Queue()
    queue.enqueue(1)
    queue.enqueue(2)
    queue.enqueue(3)
    print("Queue elements:", end=" ")
    queue.print_queue()

    print("Front element:", queue.front())

    queue.dequeue()
    print("After dequeueing, queue elements:", end=" ")
    queue.print_queue()

    print("Is queue empty?", "Yes" if queue.is_empty() else "No")

Advantages of Queues

  1. Simple to Implement: Queues have straightforward operations and are easy to implement.
  2. Efficient Operations: Enqueue and dequeue operations are performed in constant time (O(1)).

Disadvantages of Queues

  1. Fixed Size: Static queues have a fixed size, which can be limiting.
  2. Memory Inefficiency: In simple queues, even if some elements are dequeued, the unused space is not utilized efficiently.

When to Use Queues ?

Queues are preferred when:

  • You need to maintain the order of elements.
  • You need to implement scheduling and task management.
  • You need to handle real-time data streams.

Practice Problems on Queues

  1. Implement Stack using Queues
    • Problem: Implement a stack using two queues.
    • Example: MyStack stack = new MyStack(); stack.push(1); stack.push(2); stack.top(); -> Returns 2; stack.pop(); -> Returns 2; stack.empty(); -> Returns false.
  2. Number of Recent Calls
    • Problem: Implement a class RecentCounter to count the number of recent requests within a certain time frame.
    • Example: RecentCounter counter = new RecentCounter(); counter.ping(1); counter.ping(100); counter.ping(3001); -> Returns [1, 2, 3].
  3. Sliding Window Maximum
    • Problem: Given an array nums and an integer k, find the maximum for each sliding window of size k.
    • Example: Input: nums = [1,3,-1,-3,5,3,6,7], k = 3, Output: [3,3,5,5,6,7]
  4. Circular Queue Implementation
    • Problem: Design a circular queue with a fixed size.
    • Example: MyCircularQueue queue = new MyCircularQueue(3); queue.enQueue(1); queue.enQueue(2); queue.enQueue(3); queue.deQueue(); -> Returns true; queue.enQueue(4); -> Returns true.
  5. Course Schedule
    • Problem: Determine if you can finish all courses given the prerequisites.
    • Example: Input: numCourses = 2, prerequisites = [[1,0]], Output: true

Frequently Asked Questions (FAQs) on Queues

Q1: What is the difference between a queue and a stack?

  • A: A queue follows the First In, First Out (FIFO) principle, while a stack follows the Last In, First Out (LIFO) principle.

Q2: How is memory managed for queues?

  • A: In most programming languages, queues are managed by the runtime environment. For dynamic queues, memory is allocated and deallocated dynamically as elements are enqueued and dequeued.

Q3: Can queues be implemented using linked lists?

  • A: Yes, queues can be implemented using linked lists, where each node represents an element in the queue.

Q4: What are some common applications of queues?

  • A: Common applications include scheduling tasks in operating systems, handling requests in web servers, and managing tasks in print spooling.

Q5: How do you check if a queue is empty?

  • A: You can check if a queue is empty by using the isEmpty method, which returns true if the queue has no elements and false otherwise.

Q6: How do you implement a queue in a language that doesn't have built-in queue support?

  • A: You can implement a queue using arrays or linked lists by providing enqueue, dequeue, and front operations.

Q7: What is the time complexity of queue operations?

  • A: The time complexity for enqueue and dequeue operations is O(1), as they involve a constant number of operations.

Queues are a fundamental data structure that offers efficient storage and access to elements based on the First In, First Out (FIFO) principle.

DSA

Related Articles