Hone logo
Hone
Problems

Implement a Generic Queue in TypeScript

A Queue is a fundamental data structure that follows the First-In, First-Out (FIFO) principle. It's widely used in various programming scenarios, such as managing tasks, breadth-first searches, and handling requests. This challenge asks you to implement a robust and type-safe generic Queue class in TypeScript.

Problem Description

Your task is to create a Queue class in TypeScript that can store elements of any data type, specified by a generic type parameter. The queue should support the standard operations: enqueue (adding an element to the rear), dequeue (removing and returning the element from the front), peek (returning the element at the front without removing it), isEmpty (checking if the queue is empty), and size (returning the number of elements).

Key Requirements:

  • Genericity: The Queue class must be generic, accepting a type parameter T to define the type of elements it will hold.
  • enqueue(item: T): void: Adds an item to the end of the queue.
  • dequeue(): T | undefined: Removes and returns the item from the front of the queue. If the queue is empty, it should return undefined.
  • peek(): T | undefined: Returns the item at the front of the queue without removing it. If the queue is empty, it should return undefined.
  • isEmpty(): boolean: Returns true if the queue contains no elements, false otherwise.
  • size(): number: Returns the current number of elements in the queue.

Expected Behavior:

The queue should behave according to the FIFO principle. Elements added last should be removed first.

Edge Cases:

  • Dequeuing from an empty queue.
  • Peeking into an empty queue.
  • Enqueuing and dequeuing multiple elements consecutively.

Examples

Example 1:

const stringQueue = new Queue<string>();
stringQueue.enqueue("apple");
stringQueue.enqueue("banana");
console.log(stringQueue.size()); // Output: 2
console.log(stringQueue.peek()); // Output: "apple"
console.log(stringQueue.dequeue()); // Output: "apple"
console.log(stringQueue.dequeue()); // Output: "banana"
console.log(stringQueue.isEmpty()); // Output: true
console.log(stringQueue.dequeue()); // Output: undefined

Explanation: Demonstrates basic enqueue, dequeue, peek, size, and isEmpty operations with strings.

Example 2:

interface User {
  id: number;
  name: string;
}

const userQueue = new Queue<User>();
userQueue.enqueue({ id: 1, name: "Alice" });
userQueue.enqueue({ id: 2, name: "Bob" });
console.log(userQueue.peek()); // Output: { id: 1, name: "Alice" }
const dequeuedUser = userQueue.dequeue();
console.log(dequeuedUser); // Output: { id: 1, name: "Alice" }
console.log(userQueue.size()); // Output: 1

Explanation: Shows how the generic queue can handle complex object types like User.

Example 3:

const numberQueue = new Queue<number>();
console.log(numberQueue.isEmpty()); // Output: true
console.log(numberQueue.peek()); // Output: undefined
console.log(numberQueue.dequeue()); // Output: undefined
numberQueue.enqueue(10);
console.log(numberQueue.size()); // Output: 1
console.log(numberQueue.isEmpty()); // Output: false

Explanation: Covers scenarios involving an initially empty queue and then adding an element.

Constraints

  • The Queue class should be implemented using standard TypeScript features.
  • You can use built-in JavaScript data structures (like arrays) internally for implementation, but your class should provide the defined public interface.
  • The implementation should be efficient. For common operations like enqueue and dequeue, aim for O(1) time complexity if possible (depending on the underlying data structure used).

Notes

  • Consider how you will manage the elements within the queue. An array is a common choice, but think about potential performance implications for certain operations if you choose a naive implementation.
  • Ensure proper handling of undefined return types when the queue is empty.
  • The use of generics (<T>) is crucial for type safety.
Loading editor...
typescript