Data Structures
Queue Implementation
Stacks
Algorithms
Computer Science

How to implement a queue with three stacks?

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Implementing a Queue with Three Stacks

Queues and stacks are fundamental data structures that provide essential functionality in computer science and software development. A queue follows a First-In-First-Out (FIFO) principle, where the first element added is the first to be removed. In contrast, a stack follows a Last-In-First-Out (LIFO) principle, where the last element added is the first to be removed. Despite their differences, it is possible to implement a queue using stacks. This article will guide you on how to implement a queue using three stacks.

Basic Concepts

Before diving into the implementation, let's briefly refresh our knowledge on stacks and queues:

  • Stack: A collection that supports two primary operations: push (adding an element to the top) and pop (removing the top element).
  • Queue: A collection that supports two primary operations: enqueue (adding an element to the back) and dequeue (removing the front element).

Why Use Three Stacks?

While it is possible to implement a queue using two stacks, introducing a third stack can simplify the process, especially in handling corner cases, and can result in cleaner, more maintainable code. The three stacks used in this implementation serve different roles:

  1. Input Stack: Used to handle incoming elements.
  2. Output Stack: Used for dequeue operations.
  3. Temp Stack: Helps with element transfer and order maintenance.

Implementation Details

Let's look at how to implement this:

Pseudocode for Queue Operations

  1. Enqueue Operation
    When an element is added to the queue via the enqueue operation, it is pushed onto the input stack.
pseudo
   procedure enqueue(x)
       inputStack.push(x)
   end procedure
  1. Dequeue Operation
    The dequeue operation is slightly more complex:
    • If the output stack is empty, move all elements from the input stack to the output stack. This process maintains the FIFO order necessary for a queue. The temp stack can be used to correctly reverse the order of elements.
    • Then pop the top of the output stack, which represents the front of the queue.
pseudo
1   procedure dequeue
2       if outputStack.isEmpty()
3           while not inputStack.isEmpty()
4               tempStack.push(inputStack.pop())
5           while not tempStack.isEmpty()
6               outputStack.push(tempStack.pop())
7       if outputStack.isEmpty()
8           throw exception("Queue is empty")
9       return outputStack.pop()
10   end procedure
  1. Peek Operation
    Similar logic applies to viewing the front element with the peek operation:
pseudo
1   procedure peek
2       if outputStack.isEmpty()
3           while not inputStack.isEmpty()
4               tempStack.push(inputStack.pop())
5           while not tempStack.isEmpty()
6               outputStack.push(tempStack.pop())
7       if outputStack.isEmpty()
8           throw exception("Queue is empty")
9       return outputStack.top()
10   end procedure

Key Points Summary

AspectDescription
Data Structures UsedThree Stacks: Input Stack, Output Stack, Temp Stack
Enqueue ComplexityO(1)O(1) - Element added to the input stack
Dequeue ComplexityO(n)O(n) - Elements transferred to maintain order (worst case when output stack is empty) Usually O(1)O(1) when output stack is pre-filled
Space ComplexityO(n)O(n) - Each element exists in only one stack at any time
ScalabilityEffective for all basic queue operations with additional stack overhead

Additional Considerations

  • Memory Usage: This implementation uses additional memory compared to a two-stack solution but achieves a more straightforward logic path.
  • Use Cases: Implementing queues with stacks is mostly educational but could be useful in cases where stack operations are inherently faster due to platform optimizations.
  • Optimizations: When developing a production-grade solution, consider optimizing stack operations and balance memory usage.

Conclusion

Implementing a queue using three stacks provides a valuable exercise in algorithm design and showcases the versatility of common data structures. Although it involves more memory allocation than a direct queue implementation or a two-stack approach, it results in clearer code and may perform better in specific scenarios involving stack operation optimizations. Understanding this technique ensures a solid foundation for tackling complex data structure challenges in practice.


Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.