Hone logo
Hone
Problems

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 return nil and false. 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 return nil and false.
  • IsEmpty() bool: Returns true if the stack is empty, false otherwise.
  • 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 value pushed 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 Push operation should have an average time complexity of O(1).
  • The Pop, Peek, IsEmpty, and Size operations 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 to nil when 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.
Loading editor...
go