Loading...
Loading...

Queues in DSA: FIFO Principles & Applications

Master queue operations, implementation variants, and real-world applications. This tutorial covers BFS, priority queues, circular buffers, and common interview problems with coding examples.

Queue Usage in Systems (2023)

Task Scheduling (35%)
BFS Algorithms (30%)
Message Brokers (20%)
Other (15%)

1. Queue Fundamentals

Core Principles:

  • FIFO: First In First Out principle
  • Key Operations: Enqueue, Dequeue, Peek
  • Dynamic Size: Grows/shrinks as needed

Time Complexities:

Operation Array-based Linked List-based
Enqueue O(1)* O(1)
Dequeue O(1) O(1)
Peek O(1) O(1)
Search O(n) O(n)

* O(n) when resizing needed

Basic Implementations:

Array-based Queue


class ArrayQueue {
  constructor(capacity = 10) {
    this.items = new Array(capacity);
    this.front = 0;
    this.rear = -1;
    this.size = 0;
  }
  
  enqueue(item) {
    if (this.isFull()) this.resize();
    this.rear = (this.rear + 1) % this.items.length;
    this.items[this.rear] = item;
    this.size++;
  }
  
  dequeue() {
    if (this.isEmpty()) throw new Error("Queue underflow");
    const item = this.items[this.front];
    this.front = (this.front + 1) % this.items.length;
    this.size--;
    return item;
  }
  
  resize() {
    const newItems = new Array(this.items.length * 2);
    for (let i = 0; i < this.size; i++) {
      newItems[i] = this.items[(this.front + i) % this.items.length];
    }
    this.items = newItems;
    this.front = 0;
    this.rear = this.size - 1;
  }
}

Linked List Queue


class QueueNode {
  constructor(val, next = null) {
    this.val = val;
    this.next = next;
  }
}

class LinkedListQueue {
  constructor() {
    this.head = null;
    this.tail = null;
    this.size = 0;
  }
  
  enqueue(val) {
    const node = new QueueNode(val);
    if (this.isEmpty()) {
      this.head = this.tail = node;
    } else {
      this.tail.next = node;
      this.tail = node;
    }
    this.size++;
  }
  
  dequeue() {
    if (this.isEmpty()) throw new Error("Queue underflow");
    const val = this.head.val;
    this.head = this.head.next;
    this.size--;
    if (this.isEmpty()) this.tail = null;
    return val;
  }
}

2. Queue Applications

Classic Problems:

Breadth-First Search (BFS)


function bfs(graph, start) {
  const queue = [start];
  const visited = new Set([start]);
  const result = [];
  
  while (queue.length) {
    const node = queue.shift();
    result.push(node);
    
    for (const neighbor of graph[node]) {
      if (!visited.has(neighbor)) {
        visited.add(neighbor);
        queue.push(neighbor);
      }
    }
  }
  
  return result;
}

Recent Calls Counter


class RecentCounter {
  constructor() {
    this.queue = [];
  }
  
  ping(t) {
    this.queue.push(t);
    while (this.queue[0] < t - 3000) {
      this.queue.shift();
    }
    return this.queue.length;
  }
}

Real-world Use Cases:

  • Printers: Job scheduling
  • Web Servers: Request handling
  • CPU Scheduling: Process management
  • Event Loops: Message processing

3. Advanced Queue Techniques

Specialized Variants:

Priority Queue


class PriorityQueue {
  constructor(comparator = (a, b) => a > b) {
    this.heap = [];
    this.comparator = comparator;
  }
  
  enqueue(val) {
    this.heap.push(val);
    this.bubbleUp();
  }
  
  dequeue() {
    const root = this.heap[0];
    const last = this.heap.pop();
    if (this.heap.length > 0) {
      this.heap[0] = last;
      this.sinkDown();
    }
    return root;
  }
  
  bubbleUp() {
    let index = this.heap.length - 1;
    while (index > 0) {
      const parentIdx = Math.floor((index - 1) / 2);
      if (!this.comparator(this.heap[index], this.heap[parentIdx])) break;
      [this.heap[parentIdx], this.heap[index]] = 
        [this.heap[index], this.heap[parentIdx]];
      index = parentIdx;
    }
  }
}

Circular Queue


class CircularQueue {
  constructor(k) {
    this.queue = new Array(k);
    this.head = -1;
    this.tail = -1;
    this.size = 0;
  }
  
  enQueue(value) {
    if (this.isFull()) return false;
    if (this.isEmpty()) this.head = 0;
    this.tail = (this.tail + 1) % this.queue.length;
    this.queue[this.tail] = value;
    this.size++;
    return true;
  }
  
  deQueue() {
    if (this.isEmpty()) return false;
    if (this.head === this.tail) {
      this.head = this.tail = -1;
    } else {
      this.head = (this.head + 1) % this.queue.length;
    }
    this.size--;
    return true;
  }
}

Queue Problem-Solving Cheat Sheet

Problem Type Approach Time Complexity
BFS Traversal Standard queue O(V + E)
Sliding Window Deque for indices O(n)
Task Scheduling Priority queue O(n log n)
Recent Calls Maintain time window O(1) amortized

4. Specialized Queue Variants

Double-Ended Queue (Deque)

Insert/remove from both ends


class Deque {
  constructor() {
    this.items = [];
  }
  
  addFront(item) {
    this.items.unshift(item);
  }
  
  addRear(item) {
    this.items.push(item);
  }
  
  removeFront() {
    return this.items.shift();
  }
  
  removeRear() {
    return this.items.pop();
  }
}

Blocking Queue

Thread-safe with wait semantics


class BlockingQueue {
  constructor() {
    this.queue = [];
    this.lock = new Mutex();
    this.notEmpty = new ConditionVariable();
  }
  
  async enqueue(item) {
    await this.lock.acquire();
    try {
      this.queue.push(item);
      this.notEmpty.signal();
    } finally {
      this.lock.release();
    }
  }
  
  async dequeue() {
    await this.lock.acquire();
    try {
      while (this.queue.length === 0) {
        await this.notEmpty.wait(this.lock);
      }
      return this.queue.shift();
    } finally {
      this.lock.release();
    }
  }
}

Delay Queue

Elements available after delay


class DelayQueue {
  constructor() {
    this.queue = new PriorityQueue(
      (a, b) => a.availableAt < b.availableAt
    );
  }
  
  add(item, delayMs) {
    this.queue.enqueue({
      item,
      availableAt: Date.now() + delayMs
    });
  }
  
  poll() {
    if (this.queue.isEmpty()) return null;
    const { item, availableAt } = this.queue.peek();
    if (availableAt <= Date.now()) {
      return this.queue.dequeue().item;
    }
    return null;
  }
}

Queue Problem-Solving Checklist

✓ Handle empty queue cases (underflow)
✓ Consider circular buffers for fixed-size queues
✓ Use priority queues for ordered processing
✓ Optimize for concurrency when needed

DSA Expert Insight: Queue problems appear in 25% of technical interviews, especially in graph traversal and system design questions. Mastering both standard and priority queues is essential for efficient problem-solving.

0 Interaction
0 Views
Views
0 Likes
×
×
×
🍪 CookieConsent@Ptutorials:~

Welcome to Ptutorials

$ Allow cookies on this site ? (y/n)

top-home