DSA course menu
Stacks in Python: LIFO, Balanced Brackets and Expression Evaluation
Learn the stack data structure: last in, first out, push and pop in O(1), stacks with Python lists and linked lists, checking balanced brackets, evaluating postfix expressions and the min stack.
On this page
A stack is a collection where the last item added is the first one removed: last in, first out (LIFO). Think of a stack of plates: you put plates on top and take them from the top.
Your browser's Back button, an editor's Undo, and the call stack that runs recursive functions all work this way.
A Python list is a stack#
append and pop() both work at the end of a list, which is O(1):
stack = []
stack.append("page1") # push
stack.append("page2")
stack.append("page3")
print(stack[-1]) # peek
print(stack.pop()) # pop
print(stack.pop())
print(stack, len(stack) == 0)page3
page3
page2
['page1'] FalseNever use the front of a list as the top: insert(0, x) and pop(0) are O(n).
A stack built on a linked list#
The same operations on a linked list: push and pop at the head, both O(1), and no resizing ever.
class Node:
def __init__(self, value, next=None):
self.value, self.next = value, next
class Stack:
def __init__(self):
self.top = None
self.size = 0
def push(self, value):
self.top = Node(value, self.top)
self.size += 1
def pop(self):
if self.top is None:
raise IndexError("pop from empty stack")
value = self.top.value
self.top = self.top.next
self.size -= 1
return value
def peek(self):
return None if self.top is None else self.top.value
s = Stack()
for x in [1, 2, 3]:
s.push(x)
print(s.pop(), s.pop(), s.peek(), s.size)3 2 1 1Balanced brackets#
Is every opening bracket closed by the right kind, in the right order? A stack remembers which brackets are still open; the most recent one must close first.
def balanced(text):
pairs = {")": "(", "]": "[", "}": "{"}
stack = []
for ch in text:
if ch in "([{":
stack.append(ch)
elif ch in pairs:
if not stack or stack.pop() != pairs[ch]:
return False
return not stack # anything left open is unbalanced
for t in ["(a[b]{c})", "([)]", "((", "print(len(x))"]:
print(t, balanced(t))(a[b]{c}) True
([)] False
(( False
print(len(x)) TrueEvaluating postfix expressions#
In postfix (reverse Polish) notation the operator comes after its operands: 3 4 + 2 * means (3 + 4) × 2. A stack evaluates it in one pass: push numbers; on an operator, pop two numbers, apply it, and push the result.
def eval_postfix(expr):
stack = []
for token in expr.split():
if token in "+-*/":
b = stack.pop() # the second operand is on top
a = stack.pop()
if token == "+": stack.append(a + b)
elif token == "-": stack.append(a - b)
elif token == "*": stack.append(a * b)
else: stack.append(a / b)
else:
stack.append(float(token))
return stack.pop()
print(eval_postfix("3 4 + 2 *"))
print(eval_postfix("5 1 2 + 4 * + 3 -"))14.0
14.0The order of a and b matters for - and /: 10 2 - is 10 − 2, so the item popped first is the right-hand operand.
Min stack: the minimum in O(1)#
Support push, pop and get_min(), all in O(1). Store, next to each value, the minimum of everything at or below it:
class MinStack:
def __init__(self):
self.items = [] # pairs of (value, min so far)
def push(self, x):
current_min = min(x, self.items[-1][1]) if self.items else x
self.items.append((x, current_min))
def pop(self):
return self.items.pop()[0]
def get_min(self):
return self.items[-1][1]
m = MinStack()
for x in [5, 3, 7, 2]:
m.push(x)
print(m.get_min())
m.pop()
print(m.get_min())
m.pop()
m.pop()
print(m.get_min())2
3
5Common mistakes#
Practice#
Practice exercise
Write simplify_path(path) that simplifies a Unix-style path: . means "this folder", .. means "go up one folder" (ignored at the root), and repeated slashes count as one. "/home//user/./docs/../photos/" becomes "/home/user/photos".
Show hint
Split on /. Use a stack of folder names: skip empty parts and ., pop on .. (if the stack is not empty), and push anything else. Join with / at the end.
Show solution
def simplify_path(path):
stack = []
for part in path.split("/"):
if part in ("", "."):
continue
if part == "..":
if stack:
stack.pop()
else:
stack.append(part)
return "/" + "/".join(stack)
print(simplify_path("/home//user/./docs/../photos/"))
print(simplify_path("/../"))
print(simplify_path("/a/b/../../c"))/home/user/photos
/
/cKey takeaway#
Next: first in, first out, in Queues and Deques.
Finished this lesson?