Open In App

Implement Queue using Stacks

Last Updated : 22 Sep, 2025
Comments
Improve
Suggest changes
322 Likes
Like
Report

Implement a queue using stacks. We are allowed to use only stack data structure.

Dequeue-Operation-in-Queue-2


The queue should support the following operations:

  • enqueue(x): Insert element x at the end of the queue.
  • dequeue(): Remove the element from the front of the queue. If the queue is empty, do nothing.
  • front(): Return the element at the front of the queue. If the queue is empty, return -1.
  • size(): Return the number of elements in the queue.

[Approach 1] Making Enqueue Operation Costly - Enqueue in O(n) and Dequeue() in O(1)

A queue can be implemented using two stacks. Let the queue be represented as q, and the stacks used for its implementation be s1 and s2.

In this approach, the enqueue operation is made costly by transferring elements from s1 to s2 before adding the new element. This ensures that the elements in s2 are in the correct order for dequeuing. The dequeue operation remains efficient, as it simply involves popping elements from s2.

Enqueue(x):

  • While s1 is not empty, move all elements from s1 to s2.
  • Push x into s1.
  • Move everything back from s2 to s1.
  • This guarantees that the front of the queue is always on top of s1.

Dequeue():

  • If s1 is empty → queue is empty (underflow).
  • Otherwise, pop from s1.

Front():

  • If s1 is empty → return -1.
  • Otherwise, return the top element of s1 (since it always represents the front of the queue).

Size():

  • Return the current size of s1 (both stacks together always hold exactly n elements).
C++
#include <iostream> #include <stack> using namespace std; class myQueue {  stack<int> s1, s2; public:  // Enqueue operation (costly)  void enqueue(int x) {    // Move all elements from s1 to s2  while (!s1.empty()) {  s2.push(s1.top());  s1.pop();  }  // Push the new item into s1  s1.push(x);  // Push everything back to s1  while (!s2.empty()) {  s1.push(s2.top());  s2.pop();  }  }  // Dequeue operation  void dequeue() {  if (s1.empty()) {    // Queue underflow  return;   }    s1.pop();  }  // Front operation  int front() {  if (s1.empty()) {    // Queue empty  return -1;   }  return s1.top();  }  // Size operation  int size() {  return s1.size();  } }; // Driver code int main() {  myQueue q;  q.enqueue(1);  q.enqueue(2);  q.enqueue(3);  cout << "Front: " << q.front() << '\n';   cout << "Size: " << q.size() << '\n';   q.dequeue();   cout << "Front: " << q.front() << '\n';   cout << "Size: " << q.size() << '\n';   return 0; } 
Java
import java.util.Stack; class GfG {  static class myQueue {  Stack<Integer> s1 = new Stack<>();  Stack<Integer> s2 = new Stack<>();  // Enqueue operation (costly)  void enqueue(int x) {    // Move all elements from s1 to s2  while (!s1.isEmpty()) {  s2.push(s1.pop());  }  // Push the new item into s1  s1.push(x);  // Push everything back to s1  while (!s2.isEmpty()) {  s1.push(s2.pop());  }  }  // Dequeue operation  void dequeue() {  if (s1.isEmpty()) {    // Queue underflow  return;   }  s1.pop();  }  // Front operation  int front() {  if (s1.isEmpty()) {    // Queue empty  return -1;   }  return s1.peek();  }  // Size operation  int size() {  return s1.size();  }  }  public static void main(String[] args) {  myQueue q = new myQueue();  q.enqueue(1);  q.enqueue(2);  q.enqueue(3);  System.out.println("Front: " + q.front());   System.out.println("Size: " + q.size());     q.dequeue();    System.out.println("Front: " + q.front());  System.out.println("Size: " + q.size());   } } 
Python
class myQueue: def __init__(self): self.s1 = [] self.s2 = [] # Enqueue operation (costly) def enqueue(self, x): # Move all elements from s1 to s2 while self.s1: self.s2.append(self.s1.pop()) # Push the new item into s1 self.s1.append(x) # Move everything back to s1 while self.s2: self.s1.append(self.s2.pop()) # Dequeue operation def dequeue(self): if not self.s1: # Queue underflow return self.s1.pop() # Front operation def front(self): if not self.s1: return -1 return self.s1[-1] # Size operation def size(self): return len(self.s1) if __name__ == "__main__": q = myQueue() q.enqueue(1) q.enqueue(2) q.enqueue(3) print("Front:", q.front()) print("Size:", q.size()) q.dequeue() print("Front:", q.front()) print("Size:", q.size()) 
C#
using System; using System.Collections.Generic; class GfG {  class myQueue {  Stack<int> s1 = new Stack<int>();  Stack<int> s2 = new Stack<int>();  // Enqueue operation (costly)  public void enqueue(int x) {  // Move all elements from s1 to s2  while (s1.Count > 0) {  s2.Push(s1.Pop());  }  // Push item into s1  s1.Push(x);  // Push everything back to s1  while (s2.Count > 0) {  s1.Push(s2.Pop());  }  }  // Dequeue operation  public void dequeue() {  if (s1.Count == 0) {    // Queue underflow  return;   }  s1.Pop();  }  // Front operation  public int front() {  if (s1.Count == 0) {  return -1;   }  return s1.Peek();  }  // Size operation  public int size() {  return s1.Count;  }  }  public static void Main(string[] args) {  myQueue q = new myQueue();  q.enqueue(1);  q.enqueue(2);  q.enqueue(3);  Console.WriteLine("Front: " + q.front());   Console.WriteLine("Size: " + q.size());   q.dequeue();   Console.WriteLine("Front: " + q.front());   Console.WriteLine("Size: " + q.size());     } } 
JavaScript
class myQueue {  constructor() {  this.s1 = [];  this.s2 = [];  }  // Enqueue operation (costly)  enqueue(x) {    // Move all elements from s1 to s2  while (this.s1.length > 0) {  this.s2.push(this.s1.pop());  }  // Push the new item into s1  this.s1.push(x);  // Move everything back to s1  while (this.s2.length > 0) {  this.s1.push(this.s2.pop());  }  }  // Dequeue operation  dequeue() {  if (this.s1.length === 0) {  return;   }  this.s1.pop();  }  // Front operation  front() {  if (this.s1.length === 0) {  return -1;  }  return this.s1[this.s1.length - 1];  }  // Size operation  size() {  return this.s1.length;  } } // Driver code const q = new myQueue(); q.enqueue(1); q.enqueue(2); q.enqueue(3); console.log("Front:", q.front());  console.log("Size:", q.size());  q.dequeue();  console.log("Front:", q.front());  console.log("Size:", q.size());  

Output
Front: 1 Size: 3 Front: 2 Size: 2 

Time Complexity:

  • enqueue(x) : O(n) - Move all elements from s1 to s2, push the new element, then move back. Linear in the number of elements n.
  • dequeue() : O(1) - Just pop the top element from s1.
  • front() : O(1) - Return the top element of s1 without removing it.
  • size() : O(1) - Return the number of elements in s1.in the number of elements n.

Space Complexity: O(n) - All elements are stored in the two stacks s1 and s2. No extra space beyond that is needed.

[Approach 2] Making Dequeue Operation Costly - Enqueue in O(1) and Dequeue() in O(n)

In this approach, the new element is pushed onto the top of s1 during the enqueue operation. For the dequeue operation, if s2 is not empty then top of s2 needs to be returned. Otherwise all elements are transferred from s1 to s2, and the element at the top of s2 is returned.

enqueue(q, x)

  • Push x onto s1.

dequeue(q)

  • If both s1 and s2 are empty → queue underflow.
  • If s2 is empty while s1 is not empty, pop elements from s1 and push them to s2.
  • Pop the element from s2 and return it.

front()

  • If s2 is not empty → top of s2 is the front.
  • Else, if s1 is not empty → bottom of s1 is the front (can be accessed indirectly via transfer).
  • If both empty → queue is empty.

size()

  • Total size = s1.size() + s2.size()
C++
#include <iostream> #include <stack> using namespace std; class myQueue {  stack<int> s1, s2;   public:  // Enqueue operation (O(1))  void enqueue(int x) {  s1.push(x);  }  // Dequeue operation   void dequeue() {    // If both stacks are empty → queue underflow  if (s1.empty() && s2.empty()) return;  // If s2 is empty, move all elements from s1  if (s2.empty()) {  while (!s1.empty()) {  s2.push(s1.top());  s1.pop();  }  }  s2.pop();  }  // Return the front element without removing it  int front() {  if (!s2.empty()) return s2.top();  if (!s1.empty()) {    // Move all elements to s2 to access front  while (!s1.empty()) {  s2.push(s1.top());  s1.pop();  }  int x = s2.top();  return x;  }    // Queue empty  return -1;   }  // Return the current size of the queue  int size() {  return s1.size() + s2.size();  } }; int main() {  myQueue q;  q.enqueue(1);  q.enqueue(2);  q.enqueue(3);  cout << "Front: " << q.front() << "\n";   cout << "Size: " << q.size() << "\n";   q.dequeue();   cout << "Front: " << q.front() << "\n";   cout << "Size: " << q.size() << "\n";     return 0; } 
Java
import java.util.Stack; class GfG {  static class myQueue {  Stack<Integer> s1 = new Stack<>();  Stack<Integer> s2 = new Stack<>();  // Enqueue an item to the queue  void enqueue(int x) {  s1.push(x);  }  // Dequeue an item from the queue  void dequeue() {  if (s1.isEmpty() && s2.isEmpty()) {    // Queue underflow  return;  }  if (s2.isEmpty()) {  while (!s1.isEmpty()) {  s2.push(s1.pop());  }  }  s2.pop();  }  // Return the front element without removing it  int front() {  if (!s2.isEmpty()) {  return s2.peek();  }  if (!s1.isEmpty()) {    // Move elements to s2 to access front  while (!s1.isEmpty()) {  s2.push(s1.pop());  }  return s2.peek();  }    // Queue empty  return -1;   }  // Return the size of the queue  int size() {  return s1.size() + s2.size();  }  }  public static void main(String[] args) {  myQueue q = new myQueue();  q.enqueue(1);  q.enqueue(2);  q.enqueue(3);  System.out.println("Front: " + q.front());   System.out.println("Size: " + q.size());   q.dequeue();   System.out.println("Front: " + q.front());   System.out.println("Size: " + q.size());     } } 
Python
class myQueue: def __init__(self): self.s1 = [] self.s2 = [] # Enqueue an item to the queue def enqueue(self, x): self.s1.append(x) # Dequeue an item from the queue  def dequeue(self): if not self.s1 and not self.s2: # Queue underflow return if not self.s2: while self.s1: self.s2.append(self.s1.pop()) self.s2.pop() # Return the front element without removing it def front(self): if self.s2: return self.s2[-1] if self.s1: # Move all elements to s2 to access front while self.s1: self.s2.append(self.s1.pop()) return self.s2[-1] # Queue empty return -1 # Return the size of the queue def size(self): return len(self.s1) + len(self.s2) if __name__ == "__main__": q = myQueue() q.enqueue(1) q.enqueue(2) q.enqueue(3) print("Front:", q.front()) print("Size:", q.size()) q.dequeue() print("Front:", q.front()) print("Size:", q.size()) 
C#
using System; using System.Collections.Generic; class GfG {  class myQueue {  private Stack<int> s1 = new Stack<int>();  private Stack<int> s2 = new Stack<int>();  // Enqueue an item to the queue   public void enqueue(int x) {  s1.Push(x);  }  // Dequeue an item from the queue   public void dequeue() {  if (s1.Count == 0 && s2.Count == 0) {  return;   }  if (s2.Count == 0) {  while (s1.Count > 0) {  s2.Push(s1.Pop());  }  }  s2.Pop();  }  // Return the front element without removing it  public int front() {  if (s2.Count > 0) return s2.Peek();  if (s1.Count > 0) {  while (s1.Count > 0) {  s2.Push(s1.Pop());  }  return s2.Peek();  }  return -1;   }  // Return the size of the queue  public int size() {  return s1.Count + s2.Count;  }  }  public static void Main(string[] args) {  myQueue q = new myQueue();  q.enqueue(1);  q.enqueue(2);  q.enqueue(3);  Console.WriteLine("Front: " + q.front());   Console.WriteLine("Size: " + q.size());   q.dequeue();   Console.WriteLine("Front: " + q.front());   Console.WriteLine("Size: " + q.size());   } } 
JavaScript
class myQueue {  constructor() {  this.s1 = [];  this.s2 = [];  }  // Enqueue an item to the queue  enqueue(x) {  this.s1.push(x);  }  // Dequeue an item from the queue   dequeue() {  if (this.s1.length === 0 && this.s2.length === 0) {    // Queue underflow  return;   }  if (this.s2.length === 0) {  while (this.s1.length > 0) {  this.s2.push(this.s1.pop());  }  }  this.s2.pop();  }  // Return the front element without removing it  front() {  if (this.s2.length > 0) return this.s2[this.s2.length - 1];  if (this.s1.length > 0) {  while (this.s1.length > 0) {  this.s2.push(this.s1.pop());  }  return this.s2[this.s2.length - 1];  }    // Queue empty  return -1;   }  // Return the size of the queue  size() {  return this.s1.length + this.s2.length;  } } //Driven Code  const q = new myQueue(); q.enqueue(1); q.enqueue(2); q.enqueue(3); console.log("Front:", q.front());  console.log("Size:", q.size());  q.dequeue();  console.log("Front:", q.front());  console.log("Size:", q.size());  

Output
Front: 1 Size: 3 Front: 2 Size: 2 

Time Complexity:

  • enqueue(x) : O(1) - Simply push onto s1.
  • dequeue() : Amortized O(1), Worst-case O(n)
    => Worst-case: All elements from s1 are moved to s2 O(n).
    => Amortized: Each element is moved at most once from s1 to s2 O(1) per operation.
  • front() : Amortized O(1), Worst-case O(n)
    => Similar to dequeue: may need to move elements from s1 to s2.
  • size() : O(1) Just return the sum of lengths of s1 and s2.

Space Complexity: O(n)- s1 and s2 together hold at most n elements, where n is the number of elements in the queue.

[Approach 3] Queue Implementation Using One Stack and Recursion

A queue can be implemented using one stack and recursion. The recursion uses the call stack to temporarily hold elements while accessing the bottom element of the stack, which represents the front of the queue.

enqueue(x) :

  • Push new elements on top of the stack.
  • The stack top represents the rear of the queue.

dequeue() :

  • Recursively reach the bottom element (which is the front of the queue).
  • Remove it and return it.
  • Push back all other elements in the same order.

Front() :

  • Recursively reach the bottom element but do not remove it.
  • Push back all elements.

Size():

  • Returns the current size.
C++
#include <iostream> #include <stack> using namespace std; class myQueue { private:  // single stack for queue elements  stack<int> s;  public:  // Enqueue an item to the queue  void enqueue(int x) {  s.push(x);  }  // Dequeue an item from the queue   void dequeue() {  if (s.empty()) {  cout << "Queue Underflow\n";  return;  }  int x = s.top();  s.pop();  // If this is the last element (bottom), return it  if (s.empty())  return;  // Recursive call to pop remaining elements  dequeue();  // Push current element back  s.push(x);  return;  }  // Return the front element without removing it   int front() {  if (s.empty()) {  cout << "Queue is empty\n";  return -1;  }  int x = s.top();  s.pop();  if (s.empty()) {  s.push(x);   return x;  }  int item = front();   s.push(x);  return item;  }  // Return the current size of the queue   int size() {  return s.size();  } }; int main() {  myQueue q;  q.enqueue(1);  q.enqueue(2);  q.enqueue(3);  cout << "Front: " << q.front() << endl;   cout << "Size: " << q.size() << endl;   q.dequeue();   cout << "Front: " << q.front() << endl;   cout << "Size: " << q.size() << endl;   return 0; } 
Java
import java.util.Stack; class GFG {  static class myQueue {  private Stack<Integer> s = new Stack<>();  // Enqueue an item to the queue   void enqueue(int x) {  s.push(x);  }  // Dequeue an item from the queue   void dequeue() {  if (s.isEmpty()) {  System.out.println("Queue Underflow");  return;  }  int x = s.pop();  // If stack becomes empty after popping,  // this was the bottom (front of queue)  if (s.isEmpty()) {  return;  }  // Recursive call to remove the bottom element  dequeue();  // Restore the current element  s.push(x);  }  // Return the front element without removing it   int front() {  if (s.isEmpty()) {  System.out.println("Queue is empty");  return -1;  }  int x = s.pop();  // If this is the bottom element  if (s.isEmpty()) {  s.push(x);  return x;  }  int item = front();  // Restore stack  s.push(x);  return item;  }  // Return the current size of the queue   int size() {  return s.size();  }  }  public static void main(String[] args) {  myQueue q = new myQueue();  q.enqueue(1);  q.enqueue(2);  q.enqueue(3);  System.out.println("Front: " + q.front());   System.out.println("Size: " + q.size());   q.dequeue();   System.out.println("Front: " + q.front());   System.out.println("Size: " + q.size());   } } 
Python
class myQueue: def __init__(self): self.s = [] # Enqueue an item to the queue  def enqueue(self, x): self.s.append(x) # Dequeue an item from the queue def dequeue(self): if not self.s: print("Queue Underflow") return x = self.s.pop() if not self.s: return # Recursive call self.dequeue() # Push current element back self.s.append(x) return # Return the front element without removing it  def front(self): if not self.s: print("Queue is empty") return -1 x = self.s.pop() if not self.s: self.s.append(x) return x # recursive call item = self.front() self.s.append(x) return item # Return the current size of the queue  def size(self): return len(self.s) if __name__ == "__main__": q = myQueue() q.enqueue(1) q.enqueue(2) q.enqueue(3) print("Front:", q.front()) print("Size:", q.size()) q.dequeue() print("Front:", q.front()) print("Size:", q.size()) 
C#
using System; using System.Collections.Generic; public class myQueue {  private Stack<int> s = new Stack<int>();  // Enqueue an item to the queue   public void enqueue(int x) {  s.Push(x);  }  // Dequeue an item from the queue   public void dequeue() {  if (s.Count == 0) {  Console.WriteLine("Queue Underflow");  return;  }  int x = s.Pop();    if (s.Count == 0)  return;  // Recursive call  dequeue();  // Push current element back  s.Push(x);  return;  }  // Return the front element without removing it   public int front() {  if (s.Count == 0) {  Console.WriteLine("Queue is empty");  return -1;  }  int x = s.Pop();  if (s.Count == 0) {  s.Push(x);  return x;  }  // recursive call  int item = front();  s.Push(x);  return item;  }  // Return the current size of the queue   public int size() {  return s.Count;  } } class GFG {  static void Main(string[] args) {  myQueue q = new myQueue();  q.enqueue(1);  q.enqueue(2);  q.enqueue(3);  Console.WriteLine("Front: " + q.front());   Console.WriteLine("Size: " + q.size());   q.dequeue();   Console.WriteLine("Front: " + q.front());   Console.WriteLine("Size: " + q.size());   } } 
JavaScript
class myQueue {  constructor() {  this.s = [];  }  // Enqueue an item to the queue   enqueue(x) {  this.s.push(x);  }  // Dequeue an item from the queue   dequeue() {  if (this.s.length === 0) {  console.log("Queue Underflow");  return;  }  let x = this.s.pop();  if (this.s.length === 0) {  return;  }  // Recursive call  this.dequeue();  // Push current element back  this.s.push(x);  return;  }  // Return the front element without removing it  front() {  if (this.s.length === 0) {  console.log("Queue is empty");  return -1;  }  let x = this.s.pop();  if (this.s.length === 0) {  this.s.push(x);  return x;  }  // recursive call  let item = this.front();  this.s.push(x);  return item;  }  // Return the current size of the queue   size() {  return this.s.length;  } } // Driven Code const q = new myQueue(); q.enqueue(1); q.enqueue(2); q.enqueue(3); console.log("Front:", q.front());  console.log("Size:", q.size());  q.dequeue();  console.log("Front:", q.front());  console.log("Size:", q.size());  

Output
Front: 1 Size: 3 Front: 2 Size: 2 

Time Complexity

  • enqueue(x): O(1) - Just a single s.push(x).
  • dequeue(): O(n) - In the worst case, it pops all n elements recursively until it reaches the bottom, then pushes them back while unwinding recursion.
  • front(): O(n) - Similar to dequeue(), it traverses all elements recursively to reach the bottom and then restores them.
  • size(): O(1) - Direct call to s.size().

Auxiliary Space: O(n) due to the recursion call stack holding up to n elements temporarily.


Queue using two Stacks | DSA Problem

Explore