Circular Queue Implementation in TypeScript – Tech Incent
Circular queues are a fundamental data structure that follows the First-In-First-Out (FIFO) principle, but with a unique twist—the last element is connected to the first, forming a circular structure. In this article, we’ll delve into the TypeScript implementation of a circular queue, exploring its key components and understanding how it efficiently manages data.
Understanding Circular Queues
A circular queue consists of a fixed-size array and two pointers: a front pointer (head
) and a rear pointer (tail
). The front represents the beginning of the queue, and the rear represents the end. Unlike a standard linear queue, when the rear pointer reaches the end of the array, it wraps around to the beginning. This circular nature optimizes memory usage and facilitates a continuous flow of data.
TypeScript Implementation
Let’s break down the TypeScript implementation of a circular queue:
Interface: IQueue<T>
export interface IQueue<T> undefined; dequeue(): T
The IQueue
interface defines the structure of a circular queue, specifying properties like items
, size
, head
, and tail
. It also declares methods for enqueueing and dequeuing items.
Class: Queue<T>
export class Queue<T> implements IQueue<T> // ... (constructor and private storage) get items(): T[] // Implementation for getting items based on head and tail pointers get size(): number // Implementation for calculating the size of the queue enqueue(item: T): T
The Queue
class implements the IQueue
interface and includes private storage, head, and tail properties. Getter methods retrieve items and calculate the size based on the circular nature of the queue. Enqueue and dequeue methods add and remove items while considering the circular structure.
Example Usage
// Example usage of the circular queue (function () const queue = new Queue<string>(5); queue.enqueue("Hola1"); queue.enqueue("Hola2"); queue.enqueue("Hola3"); console.log(queue.items); // [ 'Hola1', 'Hola2', 'Hola3' ] queue.dequeue(); queue.enqueue("Hola4"); console.log(queue.items); // [ 'Hola2', 'Hola3', 'Hola4' ] console.log("Actual Size: ", queue.size); // Actual Size: 3 console.log("Head: ", queue.head); // Head: 1 console.log("Tail: ", queue.tail); // Tail: 4 )();
The example demonstrates the usage of the circular queue by enqueuing and dequeuing items and printing the current state of the queue, including its size, head, and tail pointers.
Final Circular Queue
/** * @description Queue Interface * @type interface */ export interface IQueue<T> undefined; dequeue(): T /** * @description: Circular Queue * @implements IQueue<T> * @example * ```ts * const queue = new Queue<string>(5); * queue.enqueue("Hola1"); * queue.dequeue(); * ``` */ export class Queue<T> implements IQueue<T> undefined if ((this.tail + 1) % (this._capacity + 1) === this.head) return undefined; // console.error("Queue is full!!! Maximum capacity of storage reached!!!", `Item: $item`) this._storage[this.tail] = item; this.tail = (this.tail + 1) % (this._capacity + 1); return item; /** * @return undefined When successfully remove it's return item, If failed, return undefined * * @description: Remove Item From Circler Queue * @Time-Complexity: O(1) * @Space-Complexity: O(1) */ dequeue(): T // Run (function () const queue = new Queue<string>(5); queue.enqueue("Hola1"); queue.enqueue("Hola2"); queue.enqueue("Hola3"); console.log(queue.items); // [ 'Hola1', 'Hola2', 'Hola3' ] queue.dequeue() queue.enqueue("Hola4"); console.log(queue.items); // [ 'Hola2', 'Hola3', 'Hola4' ] console.log("Actual Size: ", queue.size); // Actual Size: 3 console.log("Head: ", queue.head); // Head: 1 console.log("Tail: ", queue.tail); // Tail: 4 )();
Conclusion
Implementing a circular queue in TypeScript provides a versatile and efficient way to manage data structures, especially in scenarios where a fixed-size buffer is required. Understanding the principles behind circular queues and their TypeScript implementation can empower developers to make informed decisions about data structure choices in their applications.