Two stacks in one array is a technique that allows us to implement two separate stacks in a single array by dividing the array into two halves and treating each half as a separate stack. In this approach, we maintain two pointers to keep track of the top elements of each stack, and push and pop elements from each stack using these pointers.
In the example given, the TwoStacks class implements two stacks in a single array by dividing the internal array into two halves and using the first half for stack 1 and the second half for stack 2. The push1 and pop1 operations for stack 1 are implemented using the top1 pointer, which starts at -1 and increases by 1 with each push and decreases by 1 with each pop. Similarly, the push2 and pop2 operations for stack 2 are implemented using the top2 pointer, which starts at the end of the array (i.e., the length of the array) and decreases by 1 with each push and increases by 1 with each pop.
implementation of a two-stack data structure using a single Kotlin array:
class TwoStacks(val capacity: Int) {
private val array = arrayOfNulls<Any>(capacity)
private var top1 = -1 // index of top element of stack 1
private var top2 = capacity // index of top element of stack 2
fun push1(value: Any) {
if (top1 + 1 >= top2) {
throw IllegalStateException("Stack overflow")
}
top1++
array[top1] = value
}
fun push2(value: Any) {
if (top2 - 1 <= top1) {
throw IllegalStateException("Stack overflow")
}
top2--
array[top2] = value
}
fun pop1(): Any {
if (top1 < 0) {
throw NoSuchElementException("Stack underflow")
}
val value = array[top1]
array[top1] = null
top1--
return value!!
}
fun pop2(): Any {
if (top2 >= capacity) {
throw NoSuchElementException("Stack underflow")
}
val value = array[top2]
array[top2] = null
top2++
return value!!
}
fun peek1(): Any? {
return if (top1 >= 0) {
array[top1]
} else {
null
}
}
fun peek2(): Any? {
return if (top2 < capacity) {
array[top2]
} else {
null
}
}
}
fun main() {
val twoStacks = TwoStacks(6)
// Push some values onto stack 1
twoStacks.push1("A")
twoStacks.push1("B")
twoStacks.push1("C")
// Push some values onto stack 2
twoStacks.push2(1)
twoStacks.push2(2)
twoStacks.push2(3)
// Pop some values from stack 1
println(twoStacks.pop1()) // Output: C
println(twoStacks.pop1()) // Output: B
// Pop some values from stack 2
println(twoStacks.pop2()) // Output: 3
println(twoStacks.pop2()) // Output: 2
// Push more values onto stack 1
twoStacks.push1("X")
twoStacks.push1("Y")
twoStacks.push1("Z")
// Peek at the top elements of both stacks
println(twoStacks.peek1()) // Output: Z
println(twoStacks.peek2()) // Output: 1
}- The
TwoStacksclass is defined with a constructor that takes a single parametercapacity, which represents the maximum size of both stacks combined. - The
arrayproperty is initialized with an array ofcapacityelements, all initially set to null. - The
top1andtop2properties are initialized to -1 andcapacity, respectively. These properties represent the index of the top element in each stack. - The
push1method takes a value and adds it to the first stack. It first checks if there is enough space in the array to add the value by comparing the index of the top element of the first stack (top1) with the index of the top element of the second stack (top2). If there is not enough space, it throws anIllegalStateException. Otherwise, it incrementstop1, sets the value at that index in thearray, and returns nothing. - The
push2method takes a value and adds it to the second stack. It first checks if there is enough space in the array to add the value by comparing the index of the top element of the first stack (top1) with the index of the top element of the second stack (top2). If there is not enough space, it throws anIllegalStateException. Otherwise, it decrementstop2, sets the value at that index in thearray, and returns nothing. - The
pop1method removes and returns the top element of the first stack. It first checks if the first stack is not empty by checking if the index of the top element of the first stack (top1) is greater than or equal to 0. If it is empty, it throws aNoSuchElementException. Otherwise, it gets the value at the indextop1in thearray, sets that index to null, decrementstop1, and returns the value. - The
pop2method removes and returns the top element of the second stack. It first checks if the second stack is not empty by checking if the index of the top element of the second stack (top2) is less than thecapacityof the array. If it is empty, it throws aNoSuchElementException. Otherwise, it gets the value at the indextop2in thearray, sets that index to null, incrementstop2, and returns the value. - The
peek1method returns the top element of the first stack without removing it. It first checks if the first stack is not empty by checking if the index of the top element of the first stack (top1) is greater than or equal to 0. If it is empty, it returns null. Otherwise, it returns the value at the indextop1in thearray. - The
peek2method returns the top element of the second stack without removing it. It first checks if the second stack is not empty by checking if the index of the top element of the second stack (top2) is less than thecapacityof the array. If it is empty, it returns null. Otherwise, it returns the value at the indextop2in thearray.
Main Function:
- A new instance of the
TwoStacksclass is created with a capacity of 6, which creates an internal array of size 6 and initializes the two stack pointerstop1andtop2to -1 and 6 respectively. - Three strings (“A”, “B”, and “C”) are pushed onto stack 1 using the
push1method. - Three integers (1, 2, and 3) are pushed onto stack 2 using the
push2method. - The top two elements of stack 1 are popped and printed using the
pop1method. - The top two elements of stack 2 are popped and printed using the
pop2method. - Three more strings (“X”, “Y”, and “Z”) are pushed onto stack 1 using the
push1method. - The top elements of both stacks are peeked at and printed using the
peek1andpeek2methods.
The time complexity of the main function for the TwoStacks class is O(1) for all the operations being performed. This is because all the operations such as push, pop, and peek are implemented using simple array operations, and do not involve any loops or recursion that depend on the size of the input.
The space complexity of the TwoStacks class itself is O(n), where n is the capacity of the internal array used to implement the two stacks. However, the main function only uses a fixed amount of space to create the TwoStacks instance and perform the operations, which is independent of the input size. Therefore, the space complexity of the main function is also O(1) in this case.