Sometimes, I come across the following interview question: How to implement 3 stacks with one array ? Of course, any static allocation is not a solution.
We can generalize it to K stacks in one Array. Basic idea is to:
- Maintain a PriorityQueue as a min heap of currently free indexes in the allocation array.
- Maintain an array of size K, that holds the top of the stack, for each of the stacks.
- Create a Data class with 1) Value 2) Index of Prev element in the allocation array 3) Index of current element being pushed in the allocation array
- Maintain an allocation array of type Data
Refer the code for a working sample implementation.
import java.util.*;
public class Main
{
// A Java class to represent k stacks in a single array of size n
public static final class KStack {
/**
* PriorityQueue as min heap to keep track of the next free index in the
* backing array.
*/
private final PriorityQueue minHeap = new PriorityQueue<>((a,b) -> (a - b));
/**
* Keeps track of the top of the stack of each of the K stacks
*/
private final Data index[];
/**
* Backing array to hold the data of K stacks.
*/
private final Data array[];
public KStack(int noOfStacks, int sizeOfBackingArray) {
index = new Data[noOfStacks];
array = new Data[sizeOfBackingArray];
for(int i =0; i< sizeOfBackingArray; i++) {
minHeap.add(i);
}
}
public void push(int val, int stackNo) {
if(minHeap.isEmpty()) {
return;
}
int nextFreeIdx = minHeap.poll();
Data tos = index[stackNo];
if(tos == null) {
tos = new Data(val, -1 /* Previous elemnet's idx*/, nextFreeIdx
/* This elemnent's idx in underlying array*/);
} else {
tos = new Data(val, tos.myIndex, nextFreeIdx);
}
index[stackNo] = tos;
array[nextFreeIdx] = tos;
}
public int pop(int stackNo) {
if(minHeap.size() == array.length) {
return -1; // Maybe throw Exception?
}
Data tos = index[stackNo];
if(tos == null) {
return -1; // Maybe throw Exception?
}
minHeap.add(tos.myIndex);
array[tos.myIndex] = null;
int value = tos.value;
if(tos.prevIndex == -1) {
tos = null;
} else {
tos = array[tos.prevIndex];
}
index[stackNo] = tos;
return value;
}
}
public static final class Data {
int value;
int prevIndex;
int myIndex;
public Data(int value, int prevIndex, int myIndex) {
this.value = value;
this.prevIndex = prevIndex;
this.myIndex = myIndex;
}
@Override
public String toString() {
return "Value: " + this.value + ", prev: " + this.prevIndex + ", myIndex: " + myIndex;
}
}
// Driver program
public static void main(String[] args)
{
int noOfStacks = 3, sizeOfBackingArray = 10;
KStack ks = new KStack(noOfStacks, sizeOfBackingArray);
// Add elements to stack number 1
ks.push(11, 0);
ks.push(9, 0);
ks.push(7, 0);
// Add elements to stack number 3
ks.push(51, 2);
ks.push(54, 2);
// Add elements to stack number 2
ks.push(71, 1);
ks.push(94, 1);
ks.push(93, 1);
System.out.println("Popped from stack 3: " + ks.pop(2));
System.out.println("Popped from stack 3: " + ks.pop(2));
System.out.println("Popped from stack 3: " + ks.pop(2));
System.out.println("Popped from stack 2: " + ks.pop(1));
System.out.println("Popped from stack 1: " + ks.pop(0));
}
}