A linked list stack stores each element in a node that contains the data and a pointer to the next node, which uses extra memory. An array stack stores elements in contiguous memory without pointers.
package main import "fmt" type Node struct { value int next *Node } type Stack struct { top *Node } func (s *Stack) Push(val int) { newNode := &Node{value: val, next: s.top} s.top = newNode } func (s *Stack) Print() { current := s.top for current != nil { fmt.Printf("%d -> ", current.value) current = current.next } fmt.Println("null") } func main() { s := &Stack{} s.Push(10) s.Push(20) s.Push(30) s.Print() }
Each push adds a new node at the top, so the last pushed element (30) is printed first, followed by 20 and then 10.
Linked list stacks always push and pop in O(1) time. Array stacks usually do too, but resizing the array when full takes O(n) time occasionally.
package main import "fmt" type ArrayStack struct { data []int capacity int top int } func NewArrayStack(cap int) *ArrayStack { return &ArrayStack{data: make([]int, cap), capacity: cap, top: -1} } func (s *ArrayStack) Push(val int) { if s.top+1 == s.capacity { newCap := s.capacity * 2 newData := make([]int, newCap) copy(newData, s.data) s.data = newData s.capacity = newCap } s.top++ s.data[s.top] = val } func (s *ArrayStack) Print() { for i := 0; i <= s.top; i++ { fmt.Printf("%d ", s.data[i]) } fmt.Println() } func main() { s := NewArrayStack(2) s.Push(1) s.Push(2) s.Push(3) s.Print() }
The stack grows by doubling capacity when full. After pushing 3 elements, the stack contains 1, 2, 3 in order from bottom to top.
Linked list stacks have consistent O(1) push/pop without resizing pauses, making them suitable for real-time systems. Array stacks may have unpredictable delays due to resizing.
