Implementing a Stack with Manual Allocation in Go
This challenge asks you to implement a stack data structure in Go, but with a twist: you'll be responsible for manually managing the underlying memory allocation for the stack elements. This exercise will help you understand how stacks work at a lower level and how memory management plays a crucial role in their implementation. It's a good exercise to solidify your understanding of pointers and memory allocation in Go.
Problem Description
You are to create a Stack type in Go that implements a Last-In, First-Out (LIFO) data structure. The stack should support the following operations:
Push(value interface{}): Adds a new element to the top of the stack. You must allocate memory for the new element on the heap and store a pointer to it in the stack's internal storage.Pop() (interface{}, bool): Removes and returns the top element of the stack. If the stack is empty, it should returnnilandfalse. You must deallocate the memory previously occupied by the popped element.Peek() (interface{}, bool): Returns the top element of the stack without removing it. If the stack is empty, it should returnnilandfalse.IsEmpty() bool: Returnstrueif the stack is empty,falseotherwise.Size() int: Returns the number of elements currently in the stack.
The stack should be implemented using a slice of pointers to interface{} to allow it to store elements of any type. You are responsible for managing the memory allocated for each element pushed onto the stack.
Examples
Example 1:
Input:
- Push("hello")
- Push(123)
- Push(true)
- Pop()
- Pop()
- Peek()
- Pop()
- Pop()
Output:
"hello"
123
true
nil, false
Explanation:
The stack operations are performed as described. The final Pop() attempts to pop from an empty stack, returning nil and false.
Example 2:
Input:
- Push(1)
- Push(2)
- Size()
- IsEmpty()
Output:
2
false
Explanation:
The Size() method returns the current number of elements in the stack (2). The IsEmpty() method returns false because the stack is not empty.
Example 3: (Edge Case - Empty Stack)
Input:
- Pop()
- Peek()
Output:
nil, false
nil, false
Explanation:
Attempting to Pop() or Peek() from an empty stack results in returning nil and false.
Constraints
- The stack should be able to hold at least 1000 elements without significant performance degradation.
- The
valuepushed onto the stack can be of any type. - Memory leaks are strictly prohibited. All allocated memory must be properly deallocated when elements are popped.
- The
Pushoperation should have an average time complexity of O(1). - The
Pop,Peek,IsEmpty, andSizeoperations should have an average time complexity of O(1).
Notes
- Consider using
new()to allocate memory for the elements pushed onto the stack. - Remember to handle the case where the stack is empty gracefully.
- Pay close attention to memory management to avoid leaks. Go's garbage collector will not automatically deallocate memory you manually allocate with
new(). You are responsible for ensuring that the pointers to allocated memory are set tonilwhen the memory is no longer needed. - The
interface{}type allows you to store any type of data in the stack. When retrieving values from the stack, you may need to use type assertions to convert them back to their original types. This is outside the scope of this challenge, focus on the stack implementation itself.