Implement k stacks in an array (original) (raw)

Given two integers **n and **k. Implement **k stacks using a single array of size n. Multiple stacks must share the same array space while supporting the following operations:

**push(x, i): Push element x into the i-th stack.
**pop(i): Pop the top element from the i-th stack and return it.

Table of Content

[Naive Approach] Dividing Array into k Segments

The idea is to divide the array into fixed parts, one for each stack. If the array size is n and there are k stacks, then each stack gets n/k slots.

We maintain another array top[] of size k, where top[i] stores the index of the top element of the i-th stack. Initially, all top[i] are set to the start of their respective segments minus one (indicating empty stacks).

Push is done by incrementing top[i] and inserting the element, while pop is done by returning the element at top[i] and then decrementing it.

_Division-of-an-Array-to-Implement-k-Stacks

**Limitation: This approach leads to inefficient space utilization, since one stack may become full even when other stacks still have free space available.

C++ `

#include #include using namespace std;

class kStacks {

// main array to store elements
int *arr;    

// stores top index for each stack
int *top;    

// size of each segment
int segSize; 

public: kStacks(int n, int k) { segSize = n / k; arr = new int[n]; top = new int[k];

    // initialize top pointers
    for (int i = 0; i < k; i++)
        top[i] = i * segSize - 1;
}

// push element x into stack i
void push(int x, int i) {
    int end = (i + 1) * segSize - 1;

    if (top[i] == end) {
        cout << "Stack " << i << " overflow" << endl;
        return;
    }

    top[i]++;
    arr[top[i]] = x;
}

// pop element from stack i
int pop(int i) {
    int start = i * segSize;

    if (top[i] < start) {
        cout << "Stack " << i << " underflow" << endl;
        return -1;
    }

    int val = arr[top[i]];
    top[i]--;
    return val;
}

};

int main() { int n = 4, k = 2; kStacks st(n, k);

// Each operations has the following format:
// 1. Push operation → {1, value, stackNumber}
// 2. Pop operation  → {2, stackNumber}
vector<vector<int>> operations = {
    {1, 5, 0},  
    {1, 9, 0},
    {1, 10, 0}, 
    {1, 15, 1}, 
    {2, 0},
    {2, 1},
    {2, 1}
};

for (auto &op : operations) {
    
    if (op[0] == 1) { 
        int x = op[1], m = op[2];
        st.push(x, m);
    } else if (op[0] == 2) { 
        int m = op[1];
        int res = st.pop(m);
        if (res != -1)
            cout << "Popped Element: " << res << endl;
    }
}

return 0;

}

Java

import java.util.Vector;

class kStacks {

// main array to store elements
private int[] arr;

// stores top index for each stack
private int[] top;

// size of each segment
private int segSize;

public kStacks(int n, int k) {
    segSize = n / k;
    arr = new int[n];
    top = new int[k];

    // initialize top pointers
    for (int i = 0; i < k; i++)
        top[i] = i * segSize - 1;
}

// push element x into stack i
public void push(int x, int i) {
    int end = (i + 1) * segSize - 1;

    if (top[i] == end) {
        System.out.println("Stack " + i + " overflow");
        return;
    }

    top[i]++;
    arr[top[i]] = x;
}

// pop element from stack i
public int pop(int i) {
    int start = i * segSize;

    if (top[i] < start) {
        System.out.println("Stack " + i + " underflow");
        return -1;
    }

    int val = arr[top[i]];
    top[i]--;
    return val;
}

}

public class GfG { public static void main(String[] args) { int n = 4, k = 2; kStacks st = new kStacks(n, k);

    // Each operations has the following format:
    // 1. Push operation → {1, value, stackNumber}
    // 2. Pop operation  → {2, stackNumber}
   int[][] operations = {
        {1, 5, 0},
        {1, 9, 0},
        {1, 10, 0},
        {1, 15, 1},
        {2, 0},
        {2, 1},
        {2, 1}
    };
    
    for (int[] op : operations) {
        if (op[0] == 1) {
            int x = op[1], m = op[2];
            st.push(x, m);
        } else if (op[0] == 2) {
            int m = op[1];
            int res = st.pop(m);
            if (res != -1)
                System.out.println("Popped Element: " + res);
        }
    }
}

}

Python

class kStacks:

# main array to store elements
def __init__(self, n, k):
    self.segSize = n // k
    self.arr = [0] * n
    self.top = [i * self.segSize - 1 for i in range(k)]

# push element x into stack i
def push(self, x, i):
    end = (i + 1) * self.segSize - 1

    if self.top[i] == end:
        print(f'Stack {i} overflow')
        return

    self.top[i] += 1
    self.arr[self.top[i]] = x

# pop element from stack i
def pop(self, i):
    start = i * self.segSize

    if self.top[i] < start:
        print(f'Stack {i} underflow')
        return -1

    val = self.arr[self.top[i]]
    self.top[i] -= 1
    return val

if name == 'main': n = 4 k = 2 st = kStacks(n, k)

# Each operation has the following format:
# 1. Push operation → [1, value, stackNumber]
# 2. Pop operation  → [2, stackNumber]
operations = [
    [1, 5, 0],
    [1, 9, 0],
    [1, 10, 0],
    [1, 15, 1],
    [2, 0],
    [2, 1],
    [2, 1]
]

for op in operations:
    if op[0] == 1:
        x = op[1]
        m = op[2]
        st.push(x, m)
    elif op[0] == 2:
        m = op[1]
        res = st.pop(m)
        if res != -1:
            print(f'Popped Element: {res}')

C#

using System;

class kStacks {

// main array to store elements
private int[] arr;

// stores top index for each stack
private int[] top;

// size of each segment
private int segSize;

public kStacks(int n, int k) {
    segSize = n / k;
    arr = new int[n];
    top = new int[k];

    // initialize top pointers
    for (int i = 0; i < k; i++)
        top[i] = i * segSize - 1;
}

// push element x into stack i
public void push(int x, int i) {

    int end = (i + 1) * segSize - 1;

    if (top[i] == end) {
        Console.WriteLine("Stack " + i + " overflow");
        return;
    }

    top[i]++;
    arr[top[i]] = x;
}

// pop element from stack i
public int pop(int i) {
    
    int start = i * segSize;

    if (top[i] < start) {
        Console.WriteLine("Stack " + i + " underflow");
        return -1;
    }

    int val = arr[top[i]];
    top[i]--;
    return val;
}

}

class GfG { static void Main() { int n = 4, k = 2; kStacks st = new kStacks(n, k);

    // Each operation has the following format:
    // 1. Push operation → {1, value, stackNumber}
    // 2. Pop operation  → {2, stackNumber}
    int[][] operations = {
        new int[] {1, 5, 0},
        new int[] {1, 9, 0},
        new int[] {1, 10, 0},
        new int[] {1, 15, 1},
        new int[] {2, 0},
        new int[] {2, 1},
        new int[] {2, 1}
    };
    
    foreach (var op in operations) {
        if (op[0] == 1) {
            int x = op[1], m = op[2];
            st.push(x, m);
        } else if (op[0] == 2) {
            int m = op[1];
            int res = st.pop(m);
            if (res != -1)
                Console.WriteLine("Popped Element: " + res);
        }
    }
}

}

` JavaScript ``

class kStacks {

// main array to store elements
arr;

// stores top index for each stack
top;

// size of each segment
segSize;

constructor(n, k) {
    this.segSize = Math.floor(n / k);
    this.arr = new Array(n);
    this.top = new Array(k);

    // initialize top pointers
    for (let i = 0; i < k; i++)
        this.top[i] = i * this.segSize - 1;
}

// push element x into stack i
push(x, i) {
    const end = (i + 1) * this.segSize - 1;

    if (this.top[i] === end) {
        console.log(`Stack ${i} overflow`);
        return;
    }

    this.top[i]++;
    this.arr[this.top[i]] = x;
}

// pop element from stack i
pop(i) {
    const start = i * this.segSize;

    if (this.top[i] < start) {
        console.log(`Stack ${i} underflow`);
        return -1;
    }

    const val = this.arr[this.top[i]];
    this.top[i]--;
    return val;
}

}

// Driver Code const n = 4, k = 2; const st = new kStacks(n, k);

// Each operation has the following format: // 1. Push operation → [1, value, stackNumber] // 2. Pop operation → [2, stackNumber] const operations = [ [1, 5, 0], [1, 9, 0], [1, 10, 0], [1, 15, 1], [2, 0], [2, 1], [2, 1] ];

for (const op of operations) { if (op[0] === 1) { const x = op[1], m = op[2]; st.push(x, m); } else if (op[0] === 2) { const m = op[1]; const res = st.pop(m); if (res !== -1) console.log(Popped Element: ${res}); } }

``

Output

Stack 0 overflow Poped Element: 9 Poped Element: 15 Stack 1 underflow

**Time Complexity: O(1) for push operation and pop operation
**Auxiliary Space: O(n)

[Efficient Approach] Using Space Optimized Method

The idea is to allow all stacks to share the array dynamically instead of dividing it into fixed parts. For this, we use three additional structures:

**Push Operation:
When we push an element into stack i, we pick the first free slot from freeTop. The element is placed at this index, and the next[] array is updated to link this slot with the previous top of stack i. Finally, top[i] is updated to this new index, and freeTop moves to the next available free slot.

**Pop Operation:
When we pop from stack i, we look at the index stored in top[i]. The element at that index is removed, and top[i] is updated to the next link stored in next[]. The freed index is then added back to the free list by updating freeTop.

**Illustrations:

C++ `

#include using namespace std;

class kStacks {

// main array to store elements
int *arr;

// array to store indexes of top elements of stacks
int *top;

// array to store next entry (for free list and stack links)
int *next;

// beginning index of free list
int freeTop;

public: kStacks(int n, int k) { arr = new int[n]; top = new int[k]; next = new int[n];

    // initialize tops of all stacks as empty
    for (int i = 0; i < k; i++)
        top[i] = -1;

    // initialize free list
    freeTop = 0;
    for (int i = 0; i < n - 1; i++)
        next[i] = i + 1;
    next[n - 1] = -1;
}

// push element x into stack i
void push(int x, int i) {
    if (freeTop == -1) {
        cout << "Stack Overflow\n";
        return;
    }

    // take index from free list
    int index = freeTop;     
    
    // update free list
    freeTop = next[index];
    
    // put element in array
    arr[index] = x;          
    
    // link new element to previous top
    next[index] = top[i];    
    
    // update top of stack
    top[i] = index;          
}

// pop element from stack i
int pop(int i) {
    if (top[i] == -1) {
        cout << "Stack Underflow\n";
        return -1;
    }

    // get top index
    int index = top[i];      
    
    // update top to next element
    top[i] = next[index];    

    // add index back to free list
    next[index] = freeTop;   
    freeTop = index;

    // return popped element
    return arr[index];       
}

};

int main() { int n = 9, k = 3; kStacks st(n, k);

// Each query has the following format:
// 1. Push operation → {1, value, stackNumber}
// 2. Pop operation  → {2, stackNumber}
int operations[][3] = {
    {1, 10, 1},
    {1, 20, 1},
    {1, 30, 1},
    {1, 100, 0},
    {1, 200, 0},
    {2, 1},
    {2, 1},
    {2, 0},
    {1, 2, 2}
};

int op = sizeof(operations) / sizeof(operations[0]);

for (int i = 0; i < op; i++) {
    if (operations[i][0] == 1) {
        int x = operations[i][1], m = operations[i][2];
        st.push(x, m);
    } else if (operations[i][0] == 2) {
        int m = operations[i][1];
        int res = st.pop(m);
        if (res != -1)
            cout << "Popped Element: " << res << endl;
    }
}

return 0;

}

Java

import java.util.Arrays;

class kStacks {

// main array to store elements
private int[] arr;

// array to store indexes of top elements of stacks
private int[] top;

// array to store next entry (for free list and stack links)
private int[] next;

// beginning index of free list
private int freeTop;

public kStacks(int n, int k) {
    arr = new int[n];
    top = new int[k];
    next = new int[n];

    // initialize tops of all stacks as empty
    Arrays.fill(top, -1);

    // initialize free list
    freeTop = 0;
    for (int i = 0; i < n - 1; i++)
        next[i] = i + 1;
    next[n - 1] = -1;
}

// push element x into stack i
public void push(int x, int i) {
    if (freeTop == -1) {
        System.out.println("Stack Overflow");
        return;
    }

    // take index from free list
    int index = freeTop;

    // update free list
    freeTop = next[index];

    // put element in array
    arr[index] = x;

    // link new element to previous top
    next[index] = top[i];

    // update top of stack
    top[i] = index;
}

// pop element from stack i
public int pop(int i) {
    if (top[i] == -1) {
        System.out.println("Stack Underflow");
        return -1;
    }

    // get top index
    int index = top[i];

    // update top to next element
    top[i] = next[index];

    // add index back to free list
    next[index] = freeTop;
    freeTop = index;

    // return popped element
    return arr[index];
}

}

public class Main { public static void main(String[] args) { int n = 9, k = 3; kStacks st = new kStacks(n, k);

    // Each operation has the following format:
    // 1. Push operation → {1, value, stackNumber}
    // 2. Pop operation  → {2, stackNumber}
    int[][] operations = {
        {1, 10, 1},
        {1, 20, 1},
        {1, 30, 1},
        {1, 100, 0},
        {1, 200, 0},
        {2, 1},
        {2, 1},
        {2, 0},
        {1, 2, 2}
    };
    
    int op = operations.length;
    
    for (int i = 0; i < op; i++) {
        if (operations[i][0] == 1) {
            int x = operations[i][1], m = operations[i][2];
            st.push(x, m);
        } else if (operations[i][0] == 2) {
            int m = operations[i][1];
            int res = st.pop(m);
            if (res != -1)
                System.out.println("Popped Element: " + res);
        }
    }
}

}

Python

class kStacks:

def __init__(self, n, k):
    self.arr = [0] * n
    self.top = [-1] * k
    self.next = [0] * n
    self.freeTop = 0

    for i in range(n - 1):
        self.next[i] = i + 1
    self.next[n - 1] = -1

def push(self, x, i):
    if self.freeTop == -1:
        print("Stack Overflow")
        return

    index = self.freeTop
    self.freeTop = self.next[index]
    self.arr[index] = x
    self.next[index] = self.top[i]
    self.top[i] = index

def pop(self, i):
    if self.top[i] == -1:
        print("Stack Underflow")
        return -1

    index = self.top[i]
    self.top[i] = self.next[index]
    self.next[index] = self.freeTop
    self.freeTop = index

    return self.arr[index]

if name == 'main': n = 9 k = 3 st = kStacks(n, k)

# Each operation has the following format:
# 1. Push operation → (1, value, stackNumber)
# 2. Pop operation  → (2, stackNumber)
operations = [
    (1, 10, 1),
    (1, 20, 1),
    (1, 30, 1),
    (1, 100, 0),
    (1, 200, 0),
    (2, 1),
    (2, 1),
    (2, 0),
    (1, 2, 2)
]

for op in operations:
    if op[0] == 1:
        x, m = op[1], op[2]
        st.push(x, m)
    elif op[0] == 2:
        m = op[1]
        res = st.pop(m)
        if res != -1:
            print(f'Popped Element: {res}')

C#

using System;

public class kStacks {

// main array to store elements
private int[] arr;

// array to store indexes of top elements of stacks
private int[] top;

// array to store next entry (for free list and stack links)
private int[] next;

// beginning index of free list
private int freeTop;

public kStacks(int n, int k) {
    arr = new int[n];
    top = new int[k];
    next = new int[n];

    // initialize tops of all stacks as empty
    for (int i = 0; i < k; i++)
        top[i] = -1;

    // initialize free list
    freeTop = 0;
    for (int i = 0; i < n - 1; i++)
        next[i] = i + 1;
    next[n - 1] = -1;
}

// push element x into stack i
public void push(int x, int i) {
    if (freeTop == -1) {
        Console.WriteLine("Stack Overflow");
        return;
    }

    // take index from free list
    int index = freeTop;

    // update free list
    freeTop = next[index];

    // put element in array
    arr[index] = x;

    // link new element to previous top
    next[index] = top[i];

    // update top of stack
    top[i] = index;
}

// pop element from stack i
public int pop(int i) {
    if (top[i] == -1) {
        Console.WriteLine("Stack Underflow");
        return -1;
    }

    // get top index
    int index = top[i];

    // update top to next element
    top[i] = next[index];

    // add index back to free list
    next[index] = freeTop;
    freeTop = index;

    // return popped element
    return arr[index];
}

}

public class GfG { public static void Main(string[] args) { int n = 9, k = 3; kStacks st = new kStacks(n, k);

    // Each operation has the following format:
    // 1. Push operation → {1, value, stackNumber}
    // 2. Pop operation  → {2, stackNumber}
    int[][] operations = {
        new int[] {1, 10, 1},
        new int[] {1, 20, 1},
        new int[] {1, 30, 1},
        new int[] {1, 100, 0},
        new int[] {1, 200, 0},
        new int[] {2, 1},
        new int[] {2, 1},
        new int[] {2, 0},
        new int[] {1, 2, 2}
    };
    
    int opCount = operations.Length;
    
    for (int i = 0; i < opCount; i++) {
        if (operations[i][0] == 1) {
            int x = operations[i][1], m = operations[i][2];
            st.push(x, m);
        }
        else if (operations[i][0] == 2) {
            int m = operations[i][1];
            int res = st.pop(m);
            if (res != -1)
                Console.WriteLine("Popped Element: " + res);
        }
    }
}

}

JavaScript

class kStacks { // main array to store elements arr;

// array to store indexes of top elements of stacks
top;

// array to store next entry (for free list and stack links)
next;

// beginning index of free list
freeTop;

constructor(n, k) {
    this.arr = new Array(n);
    this.top = new Array(k);
    this.next = new Array(n);

    // initialize tops of all stacks as empty
    for (let i = 0; i < k; i++)
        this.top[i] = -1;

    // initialize free list
    this.freeTop = 0;
    for (let i = 0; i < n - 1; i++)
        this.next[i] = i + 1;
    this.next[n - 1] = -1;
}

// push element x into stack i
push(x, i) {
    if (this.freeTop === -1) {
        console.log('Stack Overflow');
        return;
    }

    // take index from free list
    let index = this.freeTop;

    // update free list
    this.freeTop = this.next[index];

    // put element in array
    this.arr[index] = x;

    // link new element to previous top
    this.next[index] = this.top[i];

    // update top of stack
    this.top[i] = index;
}

// pop element from stack i
pop(i) {
    if (this.top[i] === -1) {
        console.log('Stack Underflow');
        return -1;
    }

    // get top index
    let index = this.top[i];

    // update top to next element
    this.top[i] = this.next[index];

    // add index back to free list
    this.next[index] = this.freeTop;
    this.freeTop = index;

    // return popped element
    return this.arr[index];
}

}

// Driver Code let n = 9, k = 3; let st = new kStacks(n, k);

// Each operation has the following format: // 1. Push operation → [1, value, stackNumber] // 2. Pop operation → [2, stackNumber] let operations = [ [1, 10, 1], [1, 20, 1], [1, 30, 1], [1, 100, 0], [1, 200, 0], [2, 1], [2, 1], [2, 0], [1, 2, 2] ];

let opCount = operations.length;

for (let i = 0; i < opCount; i++) { if (operations[i][0] === 1) { let x = operations[i][1], m = operations[i][2]; st.push(x, m); } else if (operations[i][0] === 2) { let m = operations[i][1]; let res = st.pop(m); if (res !== -1) console.log('Popped Element: ' + res); } }

`

Output

Popped Element: 30 Popped Element: 20 Popped Element: 200

**Time Complexity: O(1) for push operation and pop operation
**Auxiliary Space: O(n)

**Related Article: