It takes two stacks to make a queue. By using one stack for enqueue operations and the other for dequeue operations, you can maintain the FIFO (First-In-First-Out) order of the queue. When dequeueing, if the second stack is empty, you transfer elements from the first stack to the second stack, reversing their order and allowing for proper dequeuing.
Implement queue using stack in Go
Key takeaways:
Two stacks can form one queue: We can implement a queue using two stacks, showing how different data structures can work together.
Time complexity considerations: Enqueue is efficient at
, while dequeue can take in the worst case, highlighting trade-offs with this approach. Space complexity: Both stacks may hold all queue elements, so the method requires
space.
Understanding data structures like stacks and queues is important for efficient problem-solving. These structures form the foundation of many core algorithms in Computer Science. A stack operates on the Last-In-First-Out (LIFO) principle, while a queue follows First-In-First-Out (FIFO).
Explore the differences between the LIFO and FIFO techniques in this Answer: What is the difference between LIFO and FIFO?.
In this Answer, we’ll explore how to implement a queue using two stacks in Go, combining these two fundamental data structures to solve common interview questions.
What is a queue?
A queue is a linear data structure that organizes elements in a specific order, adhering to the First-In-First-Out (FIFO) principle. In a queue, items are added at the end through the enqueue operation and removed from the front using the dequeue operation. These core functionalities ensure that elements are processed in the exact order they are added, making queues ideal for various applications such as task scheduling,
Find out more about breadth-first traversals in this Answer: What is Breadth-First Search?
Implementing queue using stacks
We can implement a queue using two stacks. The first stack, known as the input stack, is responsible for handling the enqueue operations, while the second stack, called the output stack, manages the dequeue operations. When a dequeue request is made, elements are transferred from the input stack to the output stack. This transfer reverses the order of the elements, effectively maintaining the First-In-First-Out (FIFO) behavior of the queue. By making the use of the Last-In-First-Out (LIFO) nature of stacks for temporary storage, this approach preserves the fundamental functionality of a queue.
Let's look at the following illustration for a better understanding.
Go code for implementing queue using stacks
This code demonstrates an implementation of a queue using two stacks. Enqueue operations are handled directly in the input stack, while dequeue operations utilize the output stack for temporary storage to maintain the desired order.
package mainimport ("fmt")// QueueUsingStacks struct holds two stacks for queue implementationtype QueueUsingStacks struct {inputStack []int // Stack for enqueue operationsoutputStack []int // Stack for dequeue operations}// Enqueue adds a new value to the queuefunc (qs *QueueUsingStacks) Enqueue(value int) {qs.inputStack = append(qs.inputStack, value) // Push value onto the input stack}// dequeueFromInput transfers all elements from the input stack to the output stackfunc (qs *QueueUsingStacks) dequeueFromInput() {// Transfer elements to reverse their order for FIFO behaviorfor len(qs.inputStack) > 0 {top := qs.inputStack[len(qs.inputStack)-1] // Get the top elementqs.inputStack = qs.inputStack[:len(qs.inputStack)-1] // Remove top element from input stackqs.outputStack = append(qs.outputStack, top) // Push it onto the output stack}}// Dequeue removes and returns the front element of the queuefunc (qs *QueueUsingStacks) Dequeue() int {// If output stack is empty, transfer elements from input stackif len(qs.outputStack) == 0 {qs.dequeueFromInput()}// Return the top element from the output stack if availableif len(qs.outputStack) > 0 {top := qs.outputStack[len(qs.outputStack)-1] // Get the front elementqs.outputStack = qs.outputStack[:len(qs.outputStack)-1] // Remove it from output stackreturn top // Return the dequeued value}return -1 // Return -1 if the queue is empty}func main() {queue := &QueueUsingStacks{} // Create a new queue instance// Enqueue elementsqueue.Enqueue(10)queue.Enqueue(20)queue.Enqueue(30)fmt.Println("Three elements are enqueued in the following order: 10, 20, and 30.")fmt.Println("\nNow, let's dequeue three times!")// Dequeue elements and print the resultsfmt.Println("\nDequeue:", queue.Dequeue()) // Should print 10fmt.Println("Dequeue:", queue.Dequeue()) // Should print 20fmt.Println("Dequeue:", queue.Dequeue()) // Should print 30}
Now, let's go over the code explanation:
Lines 8–11: The
QueueUsingStacksstruct defines the data structure for implementing a queue using two stacks. It contains two slices to handle queue operations:inputStack: This slice represents the first stack, used for enqueuing elements.outputStack: This slice represents the second stack, used for dequeuing elements.
Lines 14–16: The
Enqueuemethod adds a new element to the queue by appending it to theinputStack, effectively enqueuing the element.Lines 19–26: The
dequeueFromInputfunction transfers elements from theinputStackto theoutputStack, reversing their order in the process. It iterates through theinputStack, popping elements from the top and pushing them onto theoutputStack.Lines 29–41: The
Dequeuemethod removes and returns the front element from the queue.Lines 31–33: If the
outputStackis empty, the method callsdequeueFromInputto transfer elements from theinputStackto theoutputStack.Lines 35–39: The method then pops the top element from the
outputStack, effectively dequeuing the element.
Time complexity
Enqueue operation: The
Enqueuemethod appends an element to theinputStack, which is a constant-time operation. Therefore, the time complexity for the enqueue operation is. Dequeue operation: If the
outputStackis empty whenDequeueis called, all elements from theinputStackmust be transferred to theoutputStack, which requires iterating throughnelements, wherenis the number of elements in the queue. This transfer operation takes linear time. IfoutputStackis not empty, theDequeueoperation is, as it simply pops the top element from the outputStack. Therefore, the overall time complexity for the dequeue operation isin the worst case.
Space complexity
For both the enqueue and dequeue operations, the space used is proportional to the number of elements in the queue, as both inputStack and outputStack together can store all n elements. Therefore, the overall space complexity is linear in terms of the number of elements,
On that note, take a look at some other Answers that cover the similar topics:
Frequently asked questions
Haven’t found what you were looking for? Contact Us
How many stacks does it take to make a queue?
Can stacks be made by using 2 queues?
What is the difference between stacks and queues?
Why use stack instead of queue?
What are advantages of using a queue over a stack?
Free Resources