[Follow here] for daily coding insights.
DSA Series Chapter 5 : STACKS IN PYTHON — Using Arrays & Linked Lists
1. STACK IMPLEMENTATION USING ARRAY (PYTHON LIST)
Concept
In Python, an array-based stack can be efficiently implemented using the built-in list, because:
-
append()→ behaves like push -
pop()→ behaves like pop -
Both operations are O(1) amortized
Python Code – Array Based Stack
class ArrayStack:
def __init__(self):
self.stack = [] # internal list
def push(self, item):
self.stack.append(item) # O(1)
print(f"Pushed {item}")
def pop(self):
if self.is_empty():
print("Stack Underflow!")
return None
return self.stack.pop() # O(1)
def peek(self):
if self.is_empty():
print("Stack is Empty!")
return None
return self.stack[-1]
def is_empty(self):
return len(self.stack) == 0
def size(self):
return len(self.stack)
def display(self):
print("Stack (top → bottom):", self.stack[::-1])
Example Usage
s = ArrayStack()
s.push(10)
s.push(20)
s.push(30)
s.display()
print("Popped:", s.pop())
print("Top Element:", s.peek())
Time Complexity
| Operation | Complexity |
|---|---|
| Push | O(1) |
| Pop | O(1) |
| Peek | O(1) |
| Display | O(n) |
2. STACK IMPLEMENTATION USING LINKED LIST
Concept
A linked-list stack uses:
-
Each node → stores
data+ reference tonext -
top→ points to the first node (top of stack) -
Push & Pop operations occur at the head for O(1) complexity
Used when:
-
Dynamic size is needed
-
No memory wastage
Python Code – Linked List Based Stack
# Node class
class Node:
def __init__(self, data):
self.data = data
self.next = None
# Linked List Stack class
class LinkedListStack:
def __init__(self):
self.top = None
def push(self, data):
new_node = Node(data)
new_node.next = self.top
self.top = new_node
print(f"Pushed {data}")
def pop(self):
if self.is_empty():
print("Stack Underflow!")
return None
popped = self.top.data
self.top = self.top.next
return popped
def peek(self):
if self.is_empty():
print("Stack is Empty!")
return None
return self.top.data
def is_empty(self):
return self.top is None
def display(self):
print("Stack (top → bottom): ", end="")
temp = self.top
while temp:
print(temp.data, end=" ")
temp = temp.next
print()
Example Usage
s = LinkedListStack()
s.push(5)
s.push(15)
s.push(25)
s.display()
print("Popped:", s.pop())
print("Top Element:", s.peek())
Time Complexity
| Operation | Complexity |
|---|---|
| Push | O(1) |
| Pop | O(1) |
| Peek | O(1) |
| Display | O(n) |
ARRAY vs LINKED LIST STACK — Comparison Table
----------------------------------------------------
| Feature | Array (List) | Linked List |
|---|---|---|
| Dynamic Size | Yes, but slower expansion | Fully dynamic |
| Memory usage | Lower | Higher (Node overhead) |
| Implementation | Simple | Slightly complex |
| Overflow | Possible if memory full | Almost none |
| Speed | Faster indexing | No indexing |
When to Use Which?
✔ Use ArrayStack if:
-
You need fast performance
-
Size is known or moderate
-
Lower memory usage is required
✔ Use LinkedListStack if:
-
Size changes frequently
-
No memory wastage allowed
-
Constant-time insertions/removals required
STACK APPLICATIONS IN PYTHON
Labels: DSA – Stacks, Stack Applications, Python
Description:
This post covers three major applications of stacks used in real-world software systems and competitive programming: DFS traversal, expression conversion, and parenthesis validation, explained with full Python code.
---------------------------------------------------
1. APPLICATION OF STACK — Depth First Search (DFS)
Concept
DFS is normally recursive.
But recursion internally uses call stack.
We can convert DFS into iterative DFS using an explicit stack.
Used in:
-
Graph traversal
-
Path finding
-
Cycle detection
-
Topological sorting
-
Network connectivity
Python Code – Iterative DFS using Stack
def dfs_iterative(graph, start):
visited = set()
stack = [start]
while stack:
node = stack.pop()
if node not in visited:
print(node, end=" ")
visited.add(node)
# Push neighbors in reverse order
# so that left-most gets processed first
for neighbor in reversed(graph[node]):
if neighbor not in visited:
stack.append(neighbor)
def dfs_iterative(graph, start):
visited = set()
stack = [start]
while stack:
node = stack.pop()
if node not in visited:
print(node, end=" ")
visited.add(node)
# Push neighbors in reverse order
# so that left-most gets processed first
for neighbor in reversed(graph[node]):
if neighbor not in visited:
stack.append(neighbor)
Example Usage
graph = {
'A': ['B', 'C'],
'B': ['D', 'E'],
'C': ['F'],
'D': [],
'E': ['F'],
'F': []
}
dfs_iterative(graph, 'A')
graph = {
'A': ['B', 'C'],
'B': ['D', 'E'],
'C': ['F'],
'D': [],
'E': ['F'],
'F': []
}
dfs_iterative(graph, 'A')
2. APPLICATION OF STACK — Expression Conversion
Infix → Postfix (using Stack)
Concept
Infix expression: A + B * C
Postfix expression: A B C * +
Stack is used to:
-
Store operators
-
Maintain precedence
-
Ensure correct order of operations
Precedence & Associativity
| Operator | Precedence | Associativity |
|---|---|---|
| ^ | Highest | Right to Left |
| *, / | Middle | Left to Right |
| +, - | Lowest | Left to Right |
Python Code – Infix → Postfix Conversion
def precedence(op):
if op == '^':
return 3
if op in ['*', '/']:
return 2
if op in ['+', '-']:
return 1
return 0
def infix_to_postfix(expression):
stack = []
postfix = ""
for char in expression:
if char.isalnum(): # operand
postfix += char
elif char == '(':
stack.append(char)
elif char == ')':
while stack and stack[-1] != '(':
postfix += stack.pop()
stack.pop()
else: # operator
while (stack and precedence(stack[-1]) >= precedence(char)
and char != '^'): # ^ is right associative
postfix += stack.pop()
stack.append(char)
# pop remaining operators
while stack:
postfix += stack.pop()
return postfix
def precedence(op):
if op == '^':
return 3
if op in ['*', '/']:
return 2
if op in ['+', '-']:
return 1
return 0
def infix_to_postfix(expression):
stack = []
postfix = ""
for char in expression:
if char.isalnum(): # operand
postfix += char
elif char == '(':
stack.append(char)
elif char == ')':
while stack and stack[-1] != '(':
postfix += stack.pop()
stack.pop()
else: # operator
while (stack and precedence(stack[-1]) >= precedence(char)
and char != '^'): # ^ is right associative
postfix += stack.pop()
stack.append(char)
# pop remaining operators
while stack:
postfix += stack.pop()
return postfix
Example Usage
exp = "A+(B*C-(D/E^F)*G)*H"
print("Postfix:", infix_to_postfix(exp))
exp = "A+(B*C-(D/E^F)*G)*H"
print("Postfix:", infix_to_postfix(exp))
3. APPLICATION OF STACK — Parenthesis Checking
Concept
Used in:
-
Compilers
-
Expression validation
-
Syntax checking in IDEs
-
XML/HTML tag matching
We check the matching of:
-
() -
{} -
[]
Python Code – Balanced Parentheses
def is_balanced(expression):
stack = []
pairs = {')': '(', '}': '{', ']': '['}
for ch in expression:
if ch in "({[":
stack.append(ch)
elif ch in ")}]":
if not stack or stack[-1] != pairs[ch]:
return False
stack.pop()
return len(stack) == 0
def is_balanced(expression):
stack = []
pairs = {')': '(', '}': '{', ']': '['}
for ch in expression:
if ch in "({[":
stack.append(ch)
elif ch in ")}]":
if not stack or stack[-1] != pairs[ch]:
return False
stack.pop()
return len(stack) == 0
Example Usage
print(is_balanced("{(A+B)*[C-D]}")) # True
print(is_balanced("{(A+B]*C}")) # False
print(is_balanced("{(A+B)*[C-D]}")) # True
print(is_balanced("{(A+B]*C}")) # False
SUMMARY — Why Stack is Powerful
Stacks simplify:
-
Graph traversal
-
Expression parsing
-
Compiler design
-
Undo/redo operations
-
Backtracking algorithms
Understanding stack-based operations is essential for higher-level algorithms.
ALSO CHECK
ALSO CHECK
.png)
Comments
Post a Comment