This is what I found on a algorithm/interview question book, someone else had several posts on this one, but I still have some questions, here is the original text and code in the book:
implement 3 stacks using 1 array:
Approach 2:
In this approach, any stack can grow as long as there is any free space in the array.
We sequentially allocate space to the stacks and we link new blocks to the previous block. This means any new element in a stack keeps a pointer to the previous top element of that particular stack.
In this implementation, we face a problem of unused space. For example, if a stack deletes some of its elements, the deleted elements may not necessarily appear at the end of the array. So, in that case, we would not be able to use those newly freed spaces.
To overcome this deficiency, we can maintain a free list and the whole array space would be given initially to the free list. For every insertion, we would delete an entry from the free list. In case of deletion, we would simply add the index of the free cell to the free list.
In this implementation we would be able to have flexibility in terms of variable space utilization but we would need to increase the space complexity.
1 int stackSize = 300;
2 int indexUsed = 0;
3 int[] stackPointer = {-1,-1,-1};
4 StackNode[] buffer = new StackNode[stackSize * 3];
5 void push(int stackNum, int value) {
6 int lastIndex = stackPointer[stackNum];
7 stackPointer[stackNum] = indexUsed;
8 indexUsed++;
9 buffer[stackPointer[stackNum]]=new StackNode(lastIndex,value);
10 }
11 int pop(int stackNum) {
12 int value = buffer[stackPointer[stackNum]].value;
13 int lastIndex = stackPointer[stackNum];
14 stackPointer[stackNum] = buffer[stackPointer[stackNum]].previous;
15 buffer[lastIndex] = null;
16 indexUsed--;
17 return value;
18 }
19 int peek(int stack) { return buffer[stackPointer[stack]].value; }
20 boolean isEmpty(int stackNum) { return stackPointer[stackNum] == -1; }
21
22 class StackNode {
23 public int previous;
24 public int value;
25 public StackNode(int p, int v){
26 value = v;
27 previous = p;
28 }
29 }
my question is: in the mothod pop(), after setting buffer[lastIndex] to null(line 15), then indexUsed–(line 16), will the indexUsed be the head of the empty space?
let’s call the Stack Top nodes of first stack : S1, second stack : S2, third stack : S3;
what happens if:
I have s1 followed by s2 and s3 pushed before I wanted to pop s1,
index: 10 11 12 13
-------------------------------
| ... | s1 | s2 | s3 | null |
-------------------------------
the indexUsed is now 13.
Now if I want to do pop() on 1st stack,
it will become:
index: 10 11 12 13
----------------------------------
| ... | null | s2 | s3 | null |
----------------------------------
and the indexUsed is now 13– , that is 12,
so what happends if i want to push a new Node onto this array,
according to the push() method, at line 7 the indexUsed is assign to the stackPointer and is used as pushing index onto the array, wouldn’t that overwrite the s3(top node of stack3) in the 12th entry?
added:
and how do I change it to make it work?
at first glance I would think about implementing an boolean[] to keep track of the usage of each entry in the storage array, but that would be time and space consuming.
Thanks!
As far as I can tell, you are correct–it is not storing enough info to indicate holes in memory.
One of the big advantages to a stack is that it can be allocated on top of an array-list instead of a Linked List saving the memory of the previous/next pointers–this implementation eliminates that advantage–it’s difficult to imagine an application where this was actually a good solution.