A linked list stack stores each element in a node that contains data and a pointer to the next node, which uses extra memory. An array stack stores elements in contiguous memory without pointers.
class ArrayStack: def __init__(self): self.stack = [None]*3 self.top = -1 def push(self, val): if self.top == 2: print('Stack Overflow') else: self.top += 1 self.stack[self.top] = val print(f'Pushed {val}') s = ArrayStack() s.push(10) s.push(20) s.push(30) s.push(40)
The stack size is fixed at 3. The first three pushes succeed. The fourth push detects top == 2 (last index) and prints 'Stack Overflow'.
class Node: def __init__(self, val): self.val = val self.next = None class LinkedListStack: def __init__(self): self.top = None def push(self, val): new_node = Node(val) new_node.next = self.top self.top = new_node def pop(self): if self.top is None: print('Stack Underflow') return print(f'Popped {self.top.val}') self.top = self.top.next s = LinkedListStack() s.push(5) s.push(10) s.pop() s.pop() s.pop()
Push 5, then push 10 makes 10 the top. First pop removes 10, second pop removes 5, third pop finds stack empty and prints 'Stack Underflow'.
Both array and linked list stacks perform push and pop in constant time O(1) on average. Array resizing can cause occasional O(n), but average remains O(1).
Linked list stacks grow dynamically without needing to resize or allocate large contiguous memory blocks, making them suitable for unknown or large sizes.