Fixed Multi Stack:
/*
Fixed Multi Stack:
const stack = new FixedMultiStack(4)
Will create an array that is 3 * 4 in size and will partition the stack into three fixed stacks.
| stack 0 | stack 1 | stack 2 |
[ 0a, 0b, 0c, 0d, null, null, null, null, 2a, null, null, null ]
^ ^
top of 0 top of 2
| Stack No | Size | Capacity |
-----------------------------------
| 0 | 4 | 4 |
| 1 | 0 | 4 |
| 2 | 1 | 4 |
*/
// converted to js from book.
const FixedMultiStack = (function () {
const numberOfStacks = 3
let stackCapacity, values, sizes
// checks if provided stackNum is valid.
const isStackNumValid = (stackNum) => {
if (!(stackNum < numberOfStacks) && !stackNum >= 0) {
console.log('Invalid stackNum.')
return false
}
return true
}
class FixedMultiStack {
constructor(stackSize) {
stackCapacity = stackSize
//The array's size will be stackSize * numberOfStacks and initially be filled with null.
values = new Array(stackSize * numberOfStacks).fill(null)
// Array to keep track of the number of items in each stack.
sizes = new Array(numberOfStacks).fill(0)
}
get values() {
return values
}
push(stackNum, value) {
if (!isStackNumValid(stackNum)) return
if (this.isFull(stackNum)) {
console.log('Stack is full.')
return
}
sizes[stackNum]++
values[this.indexOfTop(stackNum)] = value
}
pop(stackNum) {
if (!isStackNumValid(stackNum)) return
if (this.isEmpty(stackNum)) {
console.log('Stack is empty.')
return
}
const topIndex = this.indexOfTop(stackNum),
value = values[topIndex]
values[topIndex] = null
sizes[stackNum]--
return value
}
peek(stackNum) {
if (!isStackNumValid(stackNum)) return
if (this.isEmpty(stackNum)) return 'Stack is empty.'
return values[this.indexOfTop(stackNum)]
}
isEmpty(stackNum) {
if (!isStackNumValid(stackNum)) return
return sizes[stackNum] === 0
}
isFull(stackNum) {
if (!isStackNumValid(stackNum)) return
return sizes[stackNum] === stackCapacity
}
indexOfTop(stackNum) {
if (!isStackNumValid(stackNum)) return
const offset = stackNum * stackCapacity,
size = sizes[stackNum]
return offset + size - 1
}
getStackValues(stackNum) {
if (!isStackNumValid(stackNum)) return
const items = new Array(sizes[stackNum])
for (let i = 0; i < items.length; i++) {
items[i] = values[stackNum * stackCapacity + i]
}
return items
}
}
return FixedMultiStack
})()
// Tests
const stack = new FixedMultiStack(4)
console.log('-------FixedMultiStack-------')
stack.push(0, '0 0')
stack.push(1, '1 0')
stack.push(1, '1 1')
stack.push(1, { 1: { 2: 'testo' } })
stack.push(1, '1 3')
console.log(stack.peek(2))
stack.push(2, '2 0')
console.log(stack.isFull(0))
console.log(stack.isFull(1))
console.log(stack.indexOfTop(0))
stack.push(1, 'fail')
stack.push('fail')
console.log(stack.peek(0))
console.log(stack.peek(0))
console.log(stack.values)
console.log(stack.getStackValues(1))
Multi stack:
/*
Multi Stack: Stack is instanciated with given initial size but resized based on available capacity of other stacks.
const stack = new MultiStack(3,4) //partition into three stacks of defaultSize 4
Will create an array that is 3 * 4 in size and will partition the stack into three stacks.
We start out with the following numbers,
| stack 0 | stack 1 | stack 2 |
[ 0a, 0b, 0c, 0d, null, null, null, null, 2a, null, null, null ]
stack 0 is full
| Stack No | Size | Capacity |
-----------------------------------
| 0 | 4 | 4 |
| 1 | 0 | 4 |
| 2 | 1 | 4 |
After pushing another item into stack 0,
| stack 0 | stack 1 | stack 2 |
[ 0a, 0b, 0c, 0d, 0e, null, null, null, 2a, null, null, null ]
stack 0 is full, but capacity has increased
| Stack No | Size | Capacity |
-----------------------------------
| 0 | 5 | 5 |
| 1 | 0 | 3 |
| 2 | 1 | 4 |
*/
// converted to js from book.
const MultiStack = (function () {
let values = [],
info
// Adjust index so it is within bounds (wrap if need to)
const adjustIndex = (index) => {
const max = values.length
return ((index % max) + max) % max
}
const nextIndex = (index) => {
return adjustIndex(index + 1)
}
const previousIndex = (index) => {
return adjustIndex(index - 1)
}
const shift = (stackNum) => {
const stack = info[stackNum]
// if stack is >= capacity, shift the next stack over.
if (stack.size >= stack.capacity) {
const nextStack = (stackNum + 1) % info.length
shift(nextStack)
stack.capacity++
}
// Shift all items in stack over by one.
let index = stack.lastCapacityIndex()
while (stack.isWithinStackCapacity(index)) {
values[index] = values[previousIndex(index)]
index = previousIndex(index)
}
//Adjust stack data
values[stack.start] = null
stack.start = nextIndex(stack.start)
stack.capacity--
}
// Expand stack by shifting over other stacks
const expand = (stackNum) => {
shift((stackNum + 1) % info.length)
info[stackNum].capacity++
}
class StackInfo {
constructor(start, capacity) {
this.start = start
this.capacity = capacity
this.size = 0
}
isWithinStackCapacity(index) {
if (index < 0 || index >= values.length) return false
// If index wraps around, adjust it.
const contiguousIndex = index < this.start ? index + values.length : index
const end = this.start + this.capacity
return this.start <= contiguousIndex && contiguousIndex < end
}
lastCapacityIndex() {
return adjustIndex(this.start + this.capacity - 1)
}
lastElementIndex() {
return adjustIndex(this.start + this.size - 1)
}
isFull() {
return this.size == this.capacity
}
isEmpty() {
return this.size == 0
}
}
class MultiStack {
constructor(numberOfStacks, defaultSize) {
//Will use the info array and keep track of size, capacity and the start of each stack.
info = new Array(numberOfStacks)
for (let i = 0; i < numberOfStacks; i++) {
info[i] = new StackInfo(defaultSize * i, defaultSize)
}
// each stack can be dynamically resized but numberOfStacks * defaultSize will determine the maximum length of the size of the main array.
values = new Array(numberOfStacks * defaultSize).fill(null)
}
get values() {
return values
}
get sizesAndCapacity() {
const res = {}
info.forEach((stack, i) => {
res[i] = { size: stack.size, capacity: stack.capacity }
})
return res
}
//return total number of elements in values array.
numberOfElements() {
let size = 0
for (const sd of info) {
size += sd.size
}
return size
}
allStacksAreFull() {
return this.numberOfElements() == values.length
}
push(stackNum, value) {
if (this.allStacksAreFull()) {
console.log('All stacks are full.')
return
}
const stack = info[stackNum]
if (stack.isFull()) expand(stackNum)
stack.size++
values[stack.lastElementIndex()] = value
}
pop(stackNum) {
const stack = info[stackNum]
if (stack.isEmpty()) {
console.log('Stack is empty.')
return
}
const value = values[stack.lastElementIndex()]
values[stack.lastElementIndex()] = null
stack.size--
return value
}
peek(stackNum) {
const stack = info[stackNum]
return values[stack.lastElementIndex()]
}
getStackValues(stackNum) {
const stack = info[stackNum]
const items = new Array(stack.size)
for (let i = 0; i < items.length; i++) {
items[i] = values[adjustIndex(stack.start + i)]
}
return items
}
}
return MultiStack
})()
const stack = new MultiStack(3, 4)
stack.push(0, '0a')
stack.push(0, '0b')
stack.push(0, '0c')
// stack.push(1, '1a')
// stack.push(1, '1b')
// stack.push(1, '1c')
// stack.push(1, '1d')
// stack.push(1, '1e')
// stack.push(1, '1f')
// stack.push(1, '1g')
// stack.push(1, '1h')
// stack.push(1, '1i')
// stack.push(1, '1j')
stack.push(0, '0d')
stack.push(2, '2a')
stack.push(0, '0e')
// stack.push(0, '0f')
// stack.push(0, '0e')
console.log(stack.allStacksAreFull())
console.log(stack.numberOfElements())
console.log(stack.values)
console.log(stack.peek(0))
console.log(stack.getStackValues(0))
console.log(stack.getStackValues(1))
console.log(stack.sizesAndCapacity)