Stacks & Expression Evaluation
Master the LIFO data structure that powers function calls, expression evaluation, and system operations. Learn stack implementations, applications, and notation conversions.
Stack Implementation in Python
# Stack Implementation using List (Array-based)
class Stack:
def __init__(self, capacity=None):
self.items = []
self.capacity = capacity
# Push operation - O(1) amortized
def push(self, item):
if self.is_full():
raise StackOverflowError("Stack is full!")
self.items.append(item)
# Pop operation - O(1)
def pop(self):
if self.is_empty():
raise StackUnderflowError("Stack is empty!")
return self.items.pop()
# Peek operation - O(1)
def peek(self):
if self.is_empty():
return None
return self.items[-1]
def is_empty(self):
return len(self.items) == 0
def is_full(self):
return self.capacity is not None and len(self.items) >= self.capacity
def size(self):
return len(self.items)
# String representation
def __str__(self):
return f"Stack: {self.items}"
# Postfix expression evaluation
def evaluate_postfix(expression):
stack = Stack()
operators = set(['+', '-', '*', '/', '^'])
for token in expression.split():
if token not in operators:
# Token is an operand
stack.push(float(token))
else:
# Token is an operator
operand2 = stack.pop()
operand1 = stack.pop()
if token == '+':
result = operand1 + operand2
elif token == '-':
result = operand1 - operand2
elif token == '*':
result = operand1 * operand2
elif token == '/':
result = operand1 / operand2
elif token == '^':
result = operand1 ** operand2
stack.push(result)
return stack.pop()
# Example: Evaluate "5 1 2 + 4 * + 3 -"
result = evaluate_postfix("5 1 2 + 4 * + 3 -")
print(f"Result: {result}") # Output: 14
# Balanced parentheses checker
def is_balanced(parentheses):
stack = Stack()
matching = {')': '(', '}': '{', ']': '['}
for char in parentheses:
if char in '({[':
stack.push(char)
elif char in ')}]':
if stack.is_empty() or stack.pop() != matching[char]:
return False
return stack.is_empty()
1. Stack Implementation
- Stack Concepts (LIFO – Last In First Out)
- Array-Based Stack Implementation
- Linked List-Based Stack Implementation
- Push Operation – Adding Elements
- Pop Operation – Removing Elements
- Peek/Top Operation – View Top Element
- Stack Overflow & Underflow Conditions
- Time Complexity Analysis
- Space Complexity Analysis
- Comparison: Array vs Linked List Stacks
- Dynamic Stack Resizing
- Error Handling in Stack Operations
2. Applications of Stacks
- Function Call Stack (Call Stack)
- Undo/Redo Operations in Applications
- Balanced Parentheses Checking
- Expression Evaluation (Postfix/Prefix)
- Browser Back/Forward Navigation
- Reversing a String using Stack
- Tower of Hanoi Problem
- Depth-First Search (DFS) in Graphs
- Syntax Parsing in Compilers
- Memory Management – Stack Memory
- Backtracking Algorithms
- Maze Solving using Stacks
3. Expression Notations
- Infix Notation (A + B)
- Prefix Notation (+ A B)
- Postfix Notation (A B +)
- Operator Precedence & Associativity
- Converting Infix → Prefix (Algorithm)
- Converting Infix → Postfix (Algorithm)
- Evaluating Prefix Expressions
- Evaluating Postfix Expressions
- Shunting Yard Algorithm
- Expression Tree Construction
- Parentheses Handling in Conversions
- Real-World Compiler Usage
LIFO Principle
Master Last-In-First-Out data structure fundamentals
Real Applications
Learn how stacks power real-world systems and applications
Expression Evaluation
Master infix, prefix, and postfix notations
Algorithm Mastery
Learn essential stack algorithms and their complexities
Stack Operations Visualization
LIFO Principle: Last element pushed (Item 5) is the first one popped. Peek operation returns Item 4 after pop.
Key Stack Applications
Function Call Stack
Manages function calls, local variables, and return addresses in programming languages.
Undo/Redo Operations
Text editors and software use stacks to implement undo (pop) and redo functionality.
Expression Evaluation
Compilers use stacks to evaluate arithmetic expressions in postfix notation.
Browser Navigation
Back button uses a stack to store visited pages, forward button uses another stack.
Parentheses Checking
Validates balanced parentheses, brackets, and braces in code editors.
DFS Algorithm
Depth-First Search in graphs uses stacks to track traversal paths.
Expression Notation Comparison
| Notation Type | Format | Example | Operator Position | Evaluation Method |
|---|---|---|---|---|
| Infix | Operand Operator Operand | A + B * C | Between operands | Requires parentheses or precedence rules |
| Prefix (Polish) | Operator Operand Operand | + A * B C | Before operands | Right-to-left evaluation using stack |
| Postfix (Reverse Polish) | Operand Operand Operator | A B C * + | After operands | Left-to-right evaluation using stack |
Conversion Example: Infix to Postfix
Infix Expression: A + B * C - D / E
Step-by-step conversion using Shunting Yard Algorithm:
1. Initialize empty stack and output list
2. Read tokens left to right:
- A → Add to output
- + → Push to stack
- B → Add to output
- * → Push to stack (higher precedence than +)
- C → Add to output
- - → Pop * and + from stack to output, then push -
- D → Add to output
- / → Push to stack
- E → Add to output
3. Pop remaining operators from stack
Resulting Postfix: A B C * + D E / -
Implementation Examples
Expression Evaluation in Java
// Postfix expression evaluation in Java
import java.util.Stack;
public class ExpressionEvaluator {
public static double evaluatePostfix(String expression) {
Stack stack = new Stack<>();
String[] tokens = expression.split("\\s+");
for (String token : tokens) {
if (isNumber(token)) {
stack.push(Double.parseDouble(token));
} else if (isOperator(token)) {
if (stack.size() < 2) {
throw new IllegalArgumentException("Invalid postfix expression");
}
double operand2 = stack.pop();
double operand1 = stack.pop();
double result = applyOperator(token, operand1, operand2);
stack.push(result);
}
}
if (stack.size() != 1) {
throw new IllegalArgumentException("Invalid postfix expression");
}
return stack.pop();
}
private static boolean isNumber(String token) {
try {
Double.parseDouble(token);
return true;
} catch (NumberFormatException e) {
return false;
}
}
private static boolean isOperator(String token) {
return token.equals("+") || token.equals("-") ||
token.equals("*") || token.equals("/") ||
token.equals("^");
}
private static double applyOperator(String operator,
double a, double b) {
switch (operator) {
case "+": return a + b;
case "-": return a - b;
case "*": return a * b;
case "/":
if (b == 0) throw new ArithmeticException("Division by zero");
return a / b;
case "^": return Math.pow(a, b);
default: throw new IllegalArgumentException("Invalid operator: " + operator);
}
}
// Example usage
public static void main(String[] args) {
String postfix = "5 1 2 + 4 * + 3 -";
double result = evaluatePostfix(postfix);
System.out.println("Result: " + result); // Output: 14.0
}
}
// Infix to Postfix conversion
class InfixToPostfix {
private static int precedence(char operator) {
switch (operator) {
case '+':
case '-': return 1;
case '*':
case '/': return 2;
case '^': return 3;
default: return -1;
}
}
public static String convert(String infix) {
StringBuilder postfix = new StringBuilder();
Stack stack = new Stack<>();
for (char c : infix.toCharArray()) {
if (Character.isLetterOrDigit(c)) {
postfix.append(c).append(' ');
} else if (c == '(') {
stack.push(c);
} else if (c == ')') {
while (!stack.isEmpty() && stack.peek() != '(') {
postfix.append(stack.pop()).append(' ');
}
stack.pop(); // Remove '('
} else { // Operator
while (!stack.isEmpty() && precedence(c) <= precedence(stack.peek())) {
postfix.append(stack.pop()).append(' ');
}
stack.push(c);
}
}
while (!stack.isEmpty()) {
postfix.append(stack.pop()).append(' ');
}
return postfix.toString().trim();
}
}
Linked List Stack in C++
// Linked List-based Stack in C++
#include
#include
using namespace std;
template
class StackNode {
public:
T data;
StackNode* next;
StackNode(T value) {
data = value;
next = nullptr;
}
};
template
class LinkedListStack {
private:
StackNode* top;
int count;
public:
LinkedListStack() {
top = nullptr;
count = 0;
}
// Push operation - O(1)
void push(T value) {
StackNode* newNode = new StackNode(value);
newNode->next = top;
top = newNode;
count++;
}
// Pop operation - O(1)
T pop() {
if (isEmpty()) {
throw underflow_error("Stack Underflow: Cannot pop from empty stack");
}
StackNode* temp = top;
T poppedValue = top->data;
top = top->next;
delete temp;
count--;
return poppedValue;
}
// Peek operation - O(1)
T peek() {
if (isEmpty()) {
throw underflow_error("Stack is empty");
}
return top->data;
}
bool isEmpty() {
return top == nullptr;
}
int size() {
return count;
}
// Display stack contents
void display() {
if (isEmpty()) {
cout << "Stack is empty" << endl;
return;
}
cout << "Stack (top to bottom): ";
StackNode* current = top;
while (current != nullptr) {
cout << current->data << " ";
current = current->next;
}
cout << endl;
}
// Destructor to prevent memory leaks
~LinkedListStack() {
while (!isEmpty()) {
pop();
}
}
};
// Example usage
int main() {
LinkedListStack stack;
// Push operations
stack.push(10);
stack.push(20);
stack.push(30);
stack.push(40);
cout << "Stack size: " << stack.size() << endl;
stack.display();
cout << "Top element: " << stack.peek() << endl;
// Pop operations
cout << "Popped: " << stack.pop() << endl;
cout << "Popped: " << stack.pop() << endl;
cout << "Stack size after pops: " << stack.size() << endl;
stack.display();
return 0;
}
Master Stack Data Structures Today
Join thousands of developers who have strengthened their algorithm skills with comprehensive stack training. Essential for system design, compiler construction, and coding interviews.
Start Learning Stacks Now