Queue Implementation with Two Stacks in JavaScript
This challenge asks you to implement a Queue data structure using only two Stacks. Queues follow the First-In, First-Out (FIFO) principle, while stacks follow Last-In, First-Out (LIFO). This exercise tests your understanding of data structures and your ability to creatively utilize them to achieve a desired outcome.
Problem Description
You are required to implement a QueueWithStacks class in JavaScript. This class should mimic the behavior of a standard Queue, supporting the following operations:
enqueue(item): Adds anitemto the rear of the queue.dequeue(): Removes and returns the item at the front of the queue. Returnsnullif the queue is empty.peek(): Returns the item at the front of the queue without removing it. Returnsnullif the queue is empty.isEmpty(): Returnstrueif the queue is empty,falseotherwise.
You must implement this class using only two JavaScript arrays, which will act as your stacks. You are not allowed to use any built-in queue data structures or methods. The efficiency of your implementation will be considered.
Key Requirements:
- The
enqueueoperation should be relatively efficient (ideally O(1) on average). - The
dequeueoperation might be less efficient, but it should still function correctly. - All operations must adhere to the FIFO principle of a queue.
- The class should be well-documented with comments explaining the logic.
Expected Behavior:
The class should behave exactly like a standard queue. Items added to the queue should be removed in the order they were added. The peek operation should return the next item to be dequeued without modifying the queue.
Edge Cases to Consider:
- Empty queue: Handle cases where
dequeueorpeekare called on an empty queue. - Multiple enqueues and dequeues: Ensure the FIFO order is maintained throughout a series of operations.
- Large number of operations: Consider the performance implications of your implementation.
Examples
Example 1:
Input:
enqueue(1);
enqueue(2);
enqueue(3);
dequeue();
enqueue(4);
dequeue();
peek();
Output:
1
2
3
4
Explanation: We enqueue 1, 2, and 3. Then we dequeue 1, leaving 2 and 3 in the queue. We enqueue 4, so the queue contains 2, 3, and 4. Finally, peek() returns 2.
Example 2:
Input:
enqueue("a");
enqueue("b");
dequeue();
dequeue();
dequeue();
Output:
"a"
"b"
null
Explanation: We enqueue "a" and "b". We dequeue "a" and then "b", leaving the queue empty. A subsequent dequeue() call returns null.
Example 3: (Edge Case - Empty Queue)
Input:
dequeue();
peek();
Output:
null
null
Explanation: The queue is initially empty. dequeue() and peek() both return null as expected.
Constraints
- The input
itemtoenqueuecan be any valid JavaScript data type. - The number of
enqueueanddequeueoperations can vary significantly (up to 10,000). - The space complexity of your solution should be proportional to the number of elements in the queue.
- While not strictly required, strive for an implementation where
enqueueis O(1) anddequeueis O(n) in the worst case, but performs well on average.
Notes
Think about how you can use one stack to hold the incoming elements and the other stack to temporarily store elements when dequeuing. The key is to efficiently transfer elements between the stacks to maintain the FIFO order. Consider the order in which elements are pushed and popped from each stack.