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?
Related lessons
Recommended DSA resources
- Cracking the Coding Interview by Gayle Laakmann McDowell
189 practice questions with solutions, for coding interview preparation.
Some links are affiliate links. If you buy through them, Laviyx Learn may earn a commission at no extra cost to you. As an Amazon Associate, we earn from qualifying purchases.