So far my naive approach is
type stack []int func (s *stack) Push(v int) { *s = append(*s, v) } func (s *stack) Pop() int { res:=(*s)[len(*s)-1] *s=(*s)[:len(*s)-1] return res }
it works - playground, but looks ugly and has too much dereferencing. Can I do better?
Stacks are most easily implemented in Golang using slices: An element is pushed to the stack with the built-in append function. The element is popped from the stack by slicing off the top element.
Instead of using array, we can also use linked list to implement stack. Linked list allocates the memory dynamically. However, time complexity in both the scenario is same for all the operations i.e. push, pop and peek.
You can perform the implementation of stacks in data structures using two data structures that are an array and a linked list. Array: In array implementation, the stack is formed using an array. All the operations are performed using arrays.
It's a matter of style and personal taste, your code is fine (apart from not being thread safe and panicking if you pop from an empty stack). To simplify it a bit you can work with value methods and return the stack itself, it's slightly more elegant to some tastes. i.e.
type stack []int func (s stack) Push(v int) stack { return append(s, v) } func (s stack) Pop() (stack, int) { // FIXME: What do we do if the stack is empty, though? l := len(s) return s[:l-1], s[l-1] } func main(){ s := make(stack,0) s = s.Push(1) s = s.Push(2) s = s.Push(3) s, p := s.Pop() fmt.Println(p) }
Another approach is to wrap it in a struct, so you can also easily add a mutex to avoid race conditions, etc. something like:
type stack struct { lock sync.Mutex // you don't have to do this if you don't want thread safety s []int } func NewStack() *stack { return &stack {sync.Mutex{}, make([]int,0), } } func (s *stack) Push(v int) { s.lock.Lock() defer s.lock.Unlock() s.s = append(s.s, v) } func (s *stack) Pop() (int, error) { s.lock.Lock() defer s.lock.Unlock() l := len(s.s) if l == 0 { return 0, errors.New("Empty Stack") } res := s.s[l-1] s.s = s.s[:l-1] return res, nil } func main(){ s := NewStack() s.Push(1) s.Push(2) s.Push(3) fmt.Println(s.Pop()) fmt.Println(s.Pop()) fmt.Println(s.Pop()) }
Here is a LIFO implementation using linked data structure
package stack import "sync" type element struct { data interface{} next *element } type stack struct { lock *sync.Mutex head *element Size int } func (stk *stack) Push(data interface{}) { stk.lock.Lock() element := new(element) element.data = data temp := stk.head element.next = temp stk.head = element stk.Size++ stk.lock.Unlock() } func (stk *stack) Pop() interface{} { if stk.head == nil { return nil } stk.lock.Lock() r := stk.head.data stk.head = stk.head.next stk.Size-- stk.lock.Unlock() return r } func New() *stack { stk := new(stack) stk.lock = &sync.Mutex{} return stk }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With