From 4a0c01ae391d9481ce240911eb08ce8d62e4dbd4 Mon Sep 17 00:00:00 2001 From: Ajesh DS Date: Tue, 10 Jan 2023 02:45:24 +0530 Subject: [PATCH] feat: add queue implementation using two stacks --- data_structures/stack_queue.ts | 92 ++++++++++++++++++++++++ data_structures/test/stack_queue.test.ts | 4 ++ 2 files changed, 96 insertions(+) create mode 100644 data_structures/stack_queue.ts create mode 100644 data_structures/test/stack_queue.test.ts diff --git a/data_structures/stack_queue.ts b/data_structures/stack_queue.ts new file mode 100644 index 00000000..cd27a391 --- /dev/null +++ b/data_structures/stack_queue.ts @@ -0,0 +1,92 @@ +/** + * A Stack Based Queue Implementation. + * The Queue data structure which follows the FIFO (First in First Out) rule. + * The dequeue operation in a normal stack based queue would be o(n), as the entire has to be shifted + * With the help of two stacks, the time complexity of this can be brought down to amortized-O(1). + * Here, one stack acts as an Enqueue stack where elements are added. + * The other stack acts as a dequeue stack which helps in dequeuing the elements + */ + +import { Queue } from './queue'; +import { Stack } from './stack'; + +export class StackQueue implements Queue{ + + private enqueueStack: Stack = new Stack(); + private dequeueStack: Stack = new Stack(); + + /** + * Returns the length of the Queue + * + * @returns {number} the length of the Queue + */ + length(): number { + return this.enqueueStack.length() + this.dequeueStack.length(); + } + + /** + * Checks if the queue is empty. + * + * @returns {boolean} Whether the queue is empty or not. + */ + isEmpty(): boolean { + return this.enqueueStack.isEmpty() && this.dequeueStack.isEmpty(); + } + + /** + * Adds an item to the queue. + * We always add a new item to the enqueueStack. + * @param item The item being added to the queue. + */ + enqueue(item: T): void { + this.enqueueStack.push(item); + } + + /** + * Shifts the elements from the enqueueStack to the dequeueStack + * In the worst case, all the elements from the enqueue stack needs to shifted, which needs O(n) time. + * However, after the shift, elements can de dequeued at O(1). + * This helps in dequeuing the elements in amortized O(1) time. + */ + private shift(): void { + while (!this.enqueueStack.isEmpty()) { + const enqueueStackTop = this.enqueueStack.pop(); + this.dequeueStack.push(enqueueStackTop); + } + } + + /** + * Removes an item from the queue and returns it. + * + * @throws Queue Underflow if the queue is empty. + * @returns The item that was removed from the queue. + */ + dequeue(): T { + if (this.isEmpty()) { + throw new Error("Queue Underflow"); + } + + if (this.dequeueStack.isEmpty()) { + this.shift(); + } + + return this.dequeueStack.pop(); + } + + /** + * Returns the item at the front of the queue. + * + * @returns The item at the front of the queue or null if the queue is empty. + */ + peek(): T | null { + if (this.isEmpty()) { + return null; + } + + if (this.dequeueStack.isEmpty()) { + this.shift(); + } + + return this.dequeueStack.top(); + } +} diff --git a/data_structures/test/stack_queue.test.ts b/data_structures/test/stack_queue.test.ts new file mode 100644 index 00000000..ab8240bf --- /dev/null +++ b/data_structures/test/stack_queue.test.ts @@ -0,0 +1,4 @@ +import { testQueue } from './queue'; +import { StackQueue } from '../stack_queue'; + +describe("Stack Based Queue", () => testQueue(StackQueue)); \ No newline at end of file