A Stack is a Last-In-First-Out (LIFO) data structure where elements are added and removed from the same end (the top). The UCX DSA package provides two stack implementations:
stack = Stack(capacity=5)stack.push(10)stack.push(20)stack.push(30)print(stack) # [10, 20, 30] Top: 2 Capacity: 5# Raises Exception if capacity is exceededtry: for i in range(10): stack.push(i)except Exception as e: print(e) # Capacity Reached
DynamicStack supports all the same methods as Stack:
stack = DynamicStack()# Push without capacity concernsfor i in range(100): stack.push(i)print(len(stack)) # 100# Pop elementswhile not stack.is_empty(): value = stack.pop()# Peek at topstack.push(42)print(stack.peek()) # 42
Stacks are ideal for evaluating arithmetic expressions:
from dsa.stack import Stackdef evaluate_postfix(expression): """Evaluate postfix expression using stack.""" stack = Stack() for token in expression.split(): if token.isdigit(): stack.push(int(token)) else: b = stack.pop() a = stack.pop() if token == '+': stack.push(a + b) elif token == '-': stack.push(a - b) elif token == '*': stack.push(a * b) elif token == '/': stack.push(a // b) return stack.pop()result = evaluate_postfix("5 3 + 2 *")print(result) # 16 ((5+3)*2)
Check if parentheses are balanced:
from dsa.stack import Stackdef is_balanced(expression): """Check if parentheses are balanced.""" stack = Stack() pairs = {'(': ')', '[': ']', '{': '}'} for char in expression: if char in pairs: stack.push(char) elif char in pairs.values(): if stack.is_empty(): return False if pairs[stack.pop()] != char: return False return stack.is_empty()print(is_balanced("({[]})")) # Trueprint(is_balanced("({[}])")) # Falseprint(is_balanced("((()))")) # True
Implement undo/redo functionality:
from dsa.stack import DynamicStackclass TextEditor: def __init__(self): self.text = "" self.undo_stack = DynamicStack() self.redo_stack = DynamicStack() def write(self, text): self.undo_stack.push(self.text) self.text += text # Clear redo stack on new action self.redo_stack = DynamicStack() def undo(self): if not self.undo_stack.is_empty(): self.redo_stack.push(self.text) self.text = self.undo_stack.pop() def redo(self): if not self.redo_stack.is_empty(): self.undo_stack.push(self.text) self.text = self.redo_stack.pop()editor = TextEditor()editor.write("Hello ")editor.write("World")print(editor.text) # "Hello World"editor.undo()print(editor.text) # "Hello "editor.redo()print(editor.text) # "Hello World"
Simulate function call stack:
from dsa.stack import Stackdef factorial(n): """Calculate factorial using explicit stack.""" stack = Stack() result = 1 # Push all values onto stack while n > 1: stack.push(n) n -= 1 # Pop and multiply while not stack.is_empty(): result *= stack.pop() return resultprint(factorial(5)) # 120
When to use Stack: Use when you know the maximum size in advance and want predictable memory usage.When to use DynamicStack: Use when size is unknown or varies significantly, and you want automatic memory management.