Implement Queue using Stacks
Last Updated :
22 Sep, 2025
Implement a queue using stacks. We are allowed to use only stack data structure.
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());
OutputFront: 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)
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());
OutputFront: 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());
OutputFront: 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
DSA Fundamentals
Data Structures
Algorithms
Advanced
Interview Preparation
Practice Problem