Open In App

Implement two Stacks in an Array

Last Updated : 26 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Create a data structure twoStacks that represent two stacks. Implementation of twoStacks should use only one array, i.e., both stacks should use the same array for storing elements. 

Following functions must be supported by twoStacks.

  • push1(int x) –> pushes x to first stack 
  • push2(int x) –> pushes x to second stack
  • pop1() –> pops an element from first stack and return the popped element 
  • pop2() –> pops an element from second stack and return the popped element

Examples:

Input: push1(2), push1(3), push2(4), pop1(), pop2(), pop2()
Output: [3, 4, -1]
Explanation: push1(2) the stack1 will be [2]
push1(3) the stack1 will be [2,3]
push2(4) the stack2 will be [4]
pop1() the popped element will be 3 from stack1 and stack1 will be [2]
pop2() the popped element will be 4 from stack2 and now stack2 is empty
pop2() the stack2 is now empty hence returned -1

Input: push1(1), push2(2), pop1(), push1(3), pop1(), pop1()
Output: [1, 3, -1]
Explanation: push1(1) the stack1 will be [1]
push2(2) the stack2 will be [2]
pop1() the popped element will be 1
push1(3) the stack1 will be [3]
pop1() the popped element will be 3
pop1() the stack1 is now empty hence returned -1

[Naive Approach] Dividing the space into two halves

The idea to implement two stacks is to divide the array into two halves and assign two halves to two stacks, i.e., use arr[0] to arr[n/2] for stack1, and arr[(n/2) + 1] to arr[n-1] for stack2 where arr[] is the array to be used to implement two stacks and size of array be n. 

Follow the steps below to solve the problem:

To implement push1(): First, check whether the top1 is greater than 0 

  • If it is then add an element at the top1 index and decrement top1 by 1
  • Else return Stack Overflow

To implement push2(): First, check whether top2 is less than n – 1

  • If it is then add an element at the top2 index and increment the top2 by 1
  • Else return Stack Overflow

To implement pop1(): First, check whether the top1 is less than or equal to n / 2

  • If it is then increment the top1 by 1 and return that element.
  • Else return Stack Underflow

To implement pop2(): First, check whether the top2 is greater than or equal to (n + 1) / 2

  • If it is then decrement the top2 by 1 and return that element.
  • Else return Stack Underflow
C++
#include <iostream>
#include <stdlib.h>

using namespace std;

class twoStacks {
    int* arr;
    int size;
    int top1, top2;

public:
    twoStacks(int n) 
    { 
        size = n;
        arr = new int[n]; 
        top1 = n / 2 + 1;  // top1 starts from the middle of the array + 1
        top2 = n / 2;      // top2 starts from the middle of the array
    }

    void push1(int x)
    {
        if (top1 < size) {  // Ensure there is space for stack1
            arr[top1++] = x;  // Increment top1 and then insert the element
        }
        else {
            cout << "Stack Overflow for stack1" << endl;
        }
    }

    void push2(int x)
    {
        if (top2 >= 0) {  // Ensure there is space for stack2
            arr[top2--] = x;  // Decrement top2 and then insert the element
        }
        else {
            cout << "Stack Overflow for stack2" << endl;
        }
    }

    int pop1()
    {
        if (top1 > size / 2) {  // Ensure stack1 is not empty
            return arr[--top1];  // Decrement top1 and return the element
        }
        else {
            return -1;  // Stack Underflow for stack1
        }
    }

    int pop2()
    {
        if (top2 < size / 2) {  // Ensure stack2 is not empty
            return arr[++top2];  // Increment top2 and return the element
        }
        else {
            return -1;  // Stack Underflow for stack2
        }
    }
};

int main()
{
    twoStacks ts(5);  
    ts.push1(2);
    ts.push1(3);
    ts.push2(4);
    cout << ts.pop1() << " ";  
    cout << ts.pop2() << " ";  
    cout << ts.pop2() << " ";  
    return 0;
}
Java
import java.util.Arrays;

class TwoStacks {
    int[] arr;
    int size;
    int top1, top2;

    public TwoStacks(int n) {
        size = n;
        arr = new int[n];
        top1 = n / 2 + 1;  // top1 starts from the middle of the array + 1
        top2 = n / 2;      // top2 starts from the middle of the array
    }

    void push1(int x) {
        if (top1 < size) {  // Ensure there is space for stack1
            arr[top1++] = x;  // Increment top1 and then insert the element
        } else {
            System.out.println("Stack Overflow for stack1");
        }
    }

    void push2(int x) {
        if (top2 >= 0) {  // Ensure there is space for stack2
            arr[top2--] = x;  // Decrement top2 and then insert the element
        } else {
            System.out.println("Stack Overflow for stack2");
        }
    }

    int pop1() {
        if (top1 > size / 2) {  // Ensure stack1 is not empty
            return arr[--top1];  // Decrement top1 and return the element
        } else {
            return -1;  // Stack Underflow for stack1
        }
    }

    int pop2() {
        if (top2 < size / 2) {  // Ensure stack2 is not empty
            return arr[++top2];  // Increment top2 and return the element
        } else {
            return -1;  // Stack Underflow for stack2
        }
    }

    public static void main(String[] args) {
        TwoStacks ts = new TwoStacks(5);
        ts.push1(2);
        ts.push1(3);
        ts.push2(4);
        System.out.print(ts.pop1() + " ");
        System.out.print(ts.pop2() + " ");
        System.out.print(ts.pop2() + " ");
    }
}
Python
class TwoStacks:
    def __init__(self, n):
        self.size = n
        self.arr = [0] * n
        self.top1 = n // 2 - 1  # top1 starts from the middle of the array - 1
        self.top2 = n // 2      # top2 starts from the middle of the array

    def push1(self, x):
        if self.top1 >= 0:  # Ensure there is space for stack1 (top1 should not overlap top2)
            self.top1 -= 1
            self.arr[self.top1] = x  # Insert the element
        else:
            print("Stack Overflow for stack1")

    def push2(self, x):
        if self.top2 < self.size:  # Ensure there is space for stack2 (top2 should not overlap top1)
            self.arr[self.top2] = x  # Insert the element
            self.top2 += 1
        else:
            print("Stack Overflow for stack2")

    def pop1(self):
        if self.top1 < self.size // 2 - 1:  # Ensure stack1 is not empty
            x = self.arr[self.top1]
            self.top1 += 1
            return x  # Return the element
        else:
            return -1  # Stack Underflow for stack1

    def pop2(self):
        if self.top2 > self.size // 2:  # Ensure stack2 is not empty
            self.top2 -= 1
            return self.arr[self.top2]  # Return the element
        else:
            return -1  # Stack Underflow for stack2


if __name__ == '__main__':
    ts = TwoStacks(5)
    ts.push1(2)
    ts.push1(3)
    ts.push2(4)
    print(ts.pop1(), end=' ')  
    print(ts.pop2(), end=' ')  
    print(ts.pop2(), end=' ')  
C#
using System;

class TwoStacks {
    int[] arr;
    int size;
    int top1, top2;

    public TwoStacks(int n) {
        size = n;
        arr = new int[n];
        top1 = n / 2 + 1;  // top1 starts from the middle of the array + 1
        top2 = n / 2;      // top2 starts from the middle of the array
    }

    public void Push1(int x) {
        if (top1 < size) {  // Ensure there is space for stack1
            arr[top1++] = x;  // Increment top1 and then insert the element
        } else {
            Console.WriteLine("Stack Overflow for stack1");
        }
    }

    public void Push2(int x) {
        if (top2 >= 0) {  // Ensure there is space for stack2
            arr[top2--] = x;  // Decrement top2 and then insert the element
        } else {
            Console.WriteLine("Stack Overflow for stack2");
        }
    }

    public int Pop1() {
        if (top1 > size / 2) {  // Ensure stack1 is not empty
            return arr[--top1];  // Decrement top1 and return the element
        } else {
            return -1;  // Stack Underflow for stack1
        }
    }

    public int Pop2() {
        if (top2 < size / 2) {  // Ensure stack2 is not empty
            return arr[++top2];  // Increment top2 and return the element
        } else {
            return -1;  // Stack Underflow for stack2
        }
    }

    public static void Main() {
        TwoStacks ts = new TwoStacks(5);
        ts.Push1(2);
        ts.Push1(3);
        ts.Push2(4);
        Console.Write(ts.Pop1() + " ");
        Console.Write(ts.Pop2() + " ");
        Console.Write(ts.Pop2() + " ");
    }
}
JavaScript
class TwoStacks {
    constructor(n) {
        this.size = n;
        this.arr = new Array(n);
        this.top1 = Math.floor(n / 2) + 1;  // top1 starts from the middle of the array + 1
        this.top2 = Math.floor(n / 2);      // top2 starts from the middle of the array
    }

    push1(x) {
        if (this.top1 < this.size) {  // Ensure there is space for stack1
            this.arr[this.top1++] = x;  // Increment top1 and then insert the element
        } else {
            console.log("Stack Overflow for stack1");
        }
    }

    push2(x) {
        if (this.top2 >= 0) {  // Ensure there is space for stack2
            this.arr[this.top2--] = x;  // Decrement top2 and then insert the element
        } else {
            console.log("Stack Overflow for stack2");
        }
    }

    pop1() {
        if (this.top1 > Math.floor(this.size / 2)) {  // Ensure stack1 is not empty
            return this.arr[--this.top1];  // Decrement top1 and return the element
        } else {
            return -1;  // Stack Underflow for stack1
        }
    }

    pop2() {
        if (this.top2 < Math.floor(this.size / 2)) {  // Ensure stack2 is not empty
            return this.arr[++this.top2];  // Increment top2 and return the element
        } else {
            return -1;  // Stack Underflow for stack2
        }
    }
}

const ts = new TwoStacks(5);
ts.push1(2);
ts.push1(3);
ts.push2(4);
let output = '';
output += ts.pop1() + ' ';
output += ts.pop2() + ' ';
output += ts.pop2() + ' ';
console.log(output.trim());  

Output
3 4 -1 

Time Complexity: 

  • Both Push operation: O(1)
  • Both Pop operation: O(1)

Auxiliary Space: O(n), Use of array to implement stack.

Problem in the above implementation

The problem with the approach is that we divide the array into two fixed halves, with one half reserved for stack1 and the other half for stack2. This can lead to inefficient space usage because if stack1 fills up, it cannot use the space available in the second half of the array for stack2, even if that space is not fully utilized.

To fix this, we should allow both stacks to grow dynamically towards each other. Instead of reserving a fixed half for each stack, stack1 will start from the left side of the array, and stack2 will start from the right side. They will grow towards each other. This way, if one stack fills up, the other stack can still use the remaining space. Overflow will only occur when both stacks meet in the middle.

[Expected Approach] Starting from endpoints

The idea is to start two stacks from two extreme corners of arr[]. 

Follow the steps below to solve the problem:

  • Stack1 starts from the leftmost corner of the array, the first element in stack1 is pushed at index 0 of the array. 
  • Stack2 starts from the rightmost corner of the array, the first element in stack2 is pushed at index (n-1) of the array. 
  • Both stacks grow (or shrink) in opposite directions. 
  • To check for overflow, all we need to check is for availability of space between top elements of both stacks.
  • To check for underflow, all we need to check is if the value of the top of the both stacks is between 0 to (n-1) or not.
C++
#include <iostream>
using namespace std;

class twoStacks {
    int *arr;
    int size;
    int top1, top2;

  public:
    twoStacks(int n) {
        size = n;
        arr = new int[n];
        top1 = -1;
        top2 = size;
    }

    void push1(int x) {
        if (top1 < top2 - 1) {
            top1++;
            arr[top1] = x;
        }
    }

    void push2(int x) {
        if (top1 < top2 - 1) {
            top2--;
            arr[top2] = x;
        }
    }

    int pop1() {
        if (top1 >= 0) {
            int x = arr[top1];
            top1--;
            return x;
        } else
            return -1;
    }

    int pop2() {
        if (top2 < size) {
            int x = arr[top2];
            top2++;
            return x;
        } else
            return -1;
    }
};

int main() {
    twoStacks ts(5);  
    ts.push1(2);     
    ts.push1(3);      
    ts.push2(4);      

    cout << ts.pop1() << " ";  
    cout << ts.pop2() << " "; 
    cout << ts.pop2() << " ";  
    
    return 0;
}
Java
import java.util.Stack;

class TwoStacks {
    private Stack<Integer> stack1;
    private Stack<Integer> stack2;

    public TwoStacks() {
        stack1 = new Stack<>();
        stack2 = new Stack<>();
    }

    public void push1(int x) {
        stack1.push(x);
    }

    public void push2(int x) {
        stack2.push(x);
    }

    public int pop1() {
        if (!stack1.isEmpty()) {
            return stack1.pop();
        } else {
            return -1;
        }
    }

    public int pop2() {
        if (!stack2.isEmpty()) {
            return stack2.pop();
        } else {
            return -1;
        }
    }

    public static void main(String[] args) {
        TwoStacks ts = new TwoStacks();
        ts.push1(2);
        ts.push1(3);
        ts.push2(4);

        System.out.print(ts.pop1() + " ");
        System.out.print(ts.pop2() + " ");
        System.out.print(ts.pop2() + " ");
    }
}
Python
class TwoStacks:
    def __init__(self, n):
        self.size = n
        self.arr = [0] * n
        self.top1 = -1
        self.top2 = n

    def push1(self, x):
        if self.top1 < self.top2 - 1:
            self.top1 += 1
            self.arr[self.top1] = x

    def push2(self, x):
        if self.top1 < self.top2 - 1:
            self.top2 -= 1
            self.arr[self.top2] = x

    def pop1(self):
        if self.top1 >= 0:
            x = self.arr[self.top1]
            self.top1 -= 1
            return x
        return -1

    def pop2(self):
        if self.top2 < self.size:
            x = self.arr[self.top2]
            self.top2 += 1
            return x
        return -1

if __name__ == '__main__':
    ts = TwoStacks(5)
    ts.push1(2)
    ts.push1(3)
    ts.push2(4)

    print(ts.pop1(), end=' ')
    print(ts.pop2(), end=' ')
    print(ts.pop2(), end=' ')
C#
using System;
using System.Collections.Generic;

class TwoStacks {
    private Stack<int> stack1;
    private Stack<int> stack2;

    public TwoStacks() {
        stack1 = new Stack<int>();
        stack2 = new Stack<int>();
    }

    public void Push1(int x) {
        stack1.Push(x);
    }

    public void Push2(int x) {
        stack2.Push(x);
    }

    public int Pop1() {
        if (stack1.Count > 0) {
            return stack1.Pop();
        } else {
            return -1;
        }
    }

    public int Pop2() {
        if (stack2.Count > 0) {
            return stack2.Pop();
        } else {
            return -1;
        }
    }

    public static void Main() {
        TwoStacks ts = new TwoStacks();
        ts.Push1(2);
        ts.Push1(3);
        ts.Push2(4);

        Console.Write(ts.Pop1() + " ");
        Console.Write(ts.Pop2() + " ");
        Console.Write(ts.Pop2() + " ");
    }
}
JavaScript
class TwoStacks {
    constructor(n) {
        this.size = n;
        this.arr = new Array(n);
        this.top1 = -1;
        this.top2 = n;
    }

    push1(x) {
        if (this.top1 < this.top2 - 1) {
            this.top1++;
            this.arr[this.top1] = x;
        }
    }

    push2(x) {
        if (this.top1 < this.top2 - 1) {
            this.top2--;
            this.arr[this.top2] = x;
        }
    }

    pop1() {
        if (this.top1 >= 0) {
            const x = this.arr[this.top1];
            this.top1--;
            return x;
        } else {
            return -1;
        }
    }

    pop2() {
        if (this.top2 < this.size) {
            const x = this.arr[this.top2];
            this.top2++;
            return x;
        } else {
            return -1;
        }
    }
}

const ts = new TwoStacks(5);
ts.push1(2);
ts.push1(3);
ts.push2(4);

let output = '';
output += ts.pop1() + ' ';
output += ts.pop2() + ' ';
output += ts.pop2() + ' ';

console.log(output.trim());  

Output
3 4 -1 

Time Complexity: 

  • Both Push operation: O(1)
  • Both Pop operation: O(1)

Auxiliary Space: O(n), Use of the array to implement stack.



Next Article

Similar Reads