Implement k stacks in a single array
https://martinm2w.wordpress.com/2012/05/28/3-1-stack-implement-3-stacks-using-a-single-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.
https://hellosmallworld123.wordpress.com/2014/05/09/describe-how-you-could-use-a-single-array-to-implement-three-stacks/https://martinm2w.wordpress.com/2012/05/28/3-1-stack-implement-3-stacks-using-a-single-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.
The other solution is to use a pointer to keep track of the previous location for every entry. The user can add elements as long as there is free space in the array. We also need to have a free list to keep track of all the free elements that was popped. So first we add all the elements into the free list. we can only use integer to track the head of the stacks.
public
class
Stack {
int
STACKSIZE =
300
;
int
[] head = {-
1
, -
1
, -
1
};
StackNode [] s =
new
StackNode[STACKSIZE];
int
[] free =
new
int
[STACKSIZE];
int
firstFree =
0
;
public
Stack() {
for
(
int
i =
0
; i < STACKSIZE; i++) {
free[i] = i;
}
}
public
boolean
push(
int
stackNum,
int
val) {
if
(firstFree == STACKSIZE)
return
false
;
//no space to push
s[free[firstFree]] =
new
StackNode(val);
s[free[firstFree]].pre = head[stackNum];
head[stackNum] = free[firstFree];
firstFree++;
return
true
;
}
public
int
pop(
int
stackNum) {
if
(head[stackNum] == -
1
)
return
-
1
;
// empty stack
StackNode n = s[head[stackNum]];
firstFree--;
free[firstFree] = head[stackNum];
// add to freelist
head[stackNum] = n.pre;
return
n.val;
}
public
int
peek(
int
stackNum) {
if
(head[stackNum] == -
1
)
return
-
1
;
//empty stack
return
s[head[stackNum]].val;
}
}
public
class
StackNode {
int
val;
int
pre;
// only track the previous index, not the node itself
public
StackNode (
int
v) {
this
.val = v;
}
}
https://martinm2w.wordpress.com/2012/05/28/3-1-stack-implement-3-stacks-using-a-single-array/
Approach 1:
Divide the array in three equal parts and allow the individual stack to grow in that limited space (note: “[“ means inclusive, while “(“ means exclusive of the end point).
»»for stack 1, we will use [0, n/3)
»»for stack 2, we will use [n/3, 2n/3)
»»for stack 3, we will use [2n/3, n)
This solution is based on the assumption that we do not have any extra information about the usage of space by individual stacks and that we can’t either modify or use any extra space. With these constraints, we are left with no other choice but to divide equally.
»»for stack 1, we will use [0, n/3)
»»for stack 2, we will use [n/3, 2n/3)
»»for stack 3, we will use [2n/3, n)
This solution is based on the assumption that we do not have any extra information about the usage of space by individual stacks and that we can’t either modify or use any extra space. With these constraints, we are left with no other choice but to divide equally.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| int stackSize = 300 ; int [] buffer = new int [stackSize * 3 ]; int [] stackPointer = { 0 , 0 , 0 }; // stack pointers to track top elem void push( int stackNum, int value) { // Find the index of the top element in the array + 1, and increment the stack pointer int index = stackNum * stackSize + stackPointer[stackNum] + 1 ; stackPointer[stackNum]++; buffer[index] = value; } int pop( int stackNum) { int index = stackNum * stackSize + stackPointer[stackNum]; stackPointer[stackNum]--; int value = buffer[index]; buffer[index]= 0 ; return value; } int peek( int stackNum) { int index = stackNum * stackSize + stackPointer[stackNum]; return buffer[index]; } boolean isEmpty( int stackNum) { return stackPointer[stackNum] == stackNum*stackSize; } |
Not good: space wasted.
public class Q1 {
//Describe how you could use a single array to implement three stacks.
final int STACK_SIZE = 100;
int[] buffer = new int[3 * STACK_SIZE];
int[] stackPointer = {-1, -1, -1}; // relative index
void push(int stackNum, int x) {
if (isFull(stackNum))
throw new IllegalArgumentException("Stack is full!");
++stackPointer[stackNum];
buffer[getAbsIndex(stackNum)] = x;
}
int pop(int stackNum) {
int ret = peek(stackNum);
--stackPointer[stackNum];
return ret;
}
int peek(int stackNum) {
if (isEmpty(stackNum))
throw new IllegalArgumentException("Stack is empty!");
return buffer[getAbsIndex(stackNum)];
}
boolean isEmpty(int stackNum) {
return stackPointer[stackNum] == -1;
}
boolean isFull(int stackNum) {
return stackPointer[stackNum] == STACK_SIZE - 1;
}
private int getAbsIndex(int stackNum) {
return stackNum * STACK_SIZE + stackPointer[stackNum];
}
Implement 3 stacks in 1 array
Method 2 - Getting space efficient solution
Here is the procedure to do so:
- Define two stacks beginning at the array endpoints and growing in opposite directions.
- Define the third stack as starting in the middle and growing in any direction you want.
- Redefine the Push op, so that when the operation is going to overwrite other stack, you shift the whole middle stack in the opposite direction before Pushing.
So this is what happens:
- First stack grows from left to right.
- Second stack grows from right to left.
- Third stack starts from the middle. Suppose odd sized array for simplicity. Then third stack grows like this:
* * * * * * * * * * * 5 3 1 2 4
Worst case scenario is when one of the first two arrays(arrays at both ends) grows at 50% of the array. Then there is a 50% waste of the array. To optimize the efficiency the third array (i.e. the array in the middle) must be selected to be the one that grows quicker than the other two.
Space (not time) efficient. You could:
1) Define two stacks beginning at the array endpoints and growing in opposite directions.
2) Define the third stack as starting in the middle and growing in any direction you want.
3) Redefine the Push op, so that when the operation is going to overwrite other stack, you shift the whole middle stack in the opposite direction before Pushing.
You need to store the stack top for the first two stacks, and the beginning and end of the third stack in some structure.
Edit
public
class
StackMFromArray {
private
StackNode[] stackNodes =
null
;
private
static
int
CAPACITY =
10
;
private
int
freeListTop =
0
;
private
int
size =
0
;
private
int
[] stackPointers = { -
1
, -
1
, -
1
};
StackMFromArray() {
stackNodes =
new
StackNode[CAPACITY];
initFreeList();
}
private
void
initFreeList() {
for
(
int
i =
0
; i < CAPACITY; i++) {
stackNodes[i] =
new
StackNode(
0
, i +
1
);
}
}
public
void
push(
int
stackNum,
int
value)
throws
Exception {
int
freeIndex;
int
currentStackTop = stackPointers[stackNum -
1
];
freeIndex = getFreeNodeIndex();
StackNode n = stackNodes[freeIndex];
n.prev = currentStackTop;
n.value = value;
stackPointers[stackNum -
1
] = freeIndex;
}
public
StackNode pop(
int
stackNum)
throws
Exception {
int
currentStackTop = stackPointers[stackNum -
1
];
if
(currentStackTop == -
1
) {
throw
new
Exception(
"UNDERFLOW"
);
}
StackNode temp = stackNodes[currentStackTop];
stackPointers[stackNum -
1
] = temp.prev;
freeStackNode(currentStackTop);
return
temp;
}
private
int
getFreeNodeIndex()
throws
Exception {
int
temp = freeListTop;
if
(size >= CAPACITY)
throw
new
Exception(
"OVERFLOW"
);
freeListTop = stackNodes[temp].prev;
size++;
return
temp;
}
private
void
freeStackNode(
int
index) {
stackNodes[index].prev = freeListTop;
freeListTop = index;
size--;
}
http://www.geeksforgeeks.org/efficiently-implement-k-stacks-single-array/
The idea is to use two extra arrays for efficient implementation of k stacks in an array. This may not make much sense for integer stacks, but stack items can be large for example stacks of employees, students, etc where every item is of hundreds of bytes. For such large stacks, the extra space used is comparatively very less as we use two integer arrays as extra space.
Following are the two extra arrays are used:
1) top[]: This is of size k and stores indexes of top elements in all stacks.
2) next[]: This is of size n and stores indexes of next item for the items in array arr[]. Here arr[] is actual array that stores k stacks.
Together with k stacks, a stack of free slots in arr[] is also maintained. The top of this stack is stored in a variable ‘free’.
1) top[]: This is of size k and stores indexes of top elements in all stacks.
2) next[]: This is of size n and stores indexes of next item for the items in array arr[]. Here arr[] is actual array that stores k stacks.
Together with k stacks, a stack of free slots in arr[] is also maintained. The top of this stack is stored in a variable ‘free’.
All entries in top[] are initialized as -1 to indicate that all stacks are empty. All entries next[i] are initialized as i+1 because all slots are free initially and pointing to next slot. Top of free stack, ‘free’ is initialized as 0.
Read full article from Implement 3 stacks in 1 array ~ KodeKnight