Stacks
Stacks#
A stack is a linear data structure that follows the LIFO (Last-In, First-Out) principle. All insertions and deletions occur at the "top" of the stack, enabling constant-time operations.
Think of a stack of plates: you can only add or remove plates from the top.
Stack Operations#
graph LR
A[Empty Stack] --> B[Push A]
B --> C[Push B]
C --> D[Push C]
D --> E[Peek: C]
E --> F[Pop: C]
F --> G[Pop: B]
G --> H[Pop: A]
H --> I[Empty Stack]
style A fill:#f9f9f9
style I fill:#f9f9f9
style E fill:#e8f5e8
style F fill:#ffe8e8
style G fill:#ffe8e8
style H fill:#ffe8e8
Core Operations#
graph TD
A[Stack Operations] --> B[Push]
A --> C[Pop]
A --> D[Peek]
A --> E[isEmpty]
B --> B1[Add to top]
C --> C1[Remove from top]
D --> D1[View top element]
E --> E1[Check if empty]
style B fill:#c8e6c9
style C fill:#ffcdd2
style D fill:#e1f5fe
style E fill:#fff3e0
Key Properties#
- LIFO Access: Last element added is first removed
- Single Access Point: Only top element is accessible
- Constant Time: All operations are O(1)
Applications#
graph TD
A[Stack Applications] --> B[Function Calls]
A --> C[Expression Evaluation]
A --> D[Undo Operations]
A --> E[Backtracking]
B --> B1[Call Stack Management]
C --> C1[Infix/Postfix Conversion]
D --> D1[Text Editor Undo]
E --> E1[Maze Solving]
style A fill:#e3f2fd
style B fill:#c8e6c9
style C fill:#fff3e0
style D fill:#f3e5f5
style E fill:#e8f5e8
Time & Space Complexity#
| Operation | Time | Space | Description |
|---|---|---|---|
| push(item) | O(1) | O(1) | Add to top |
| pop() | O(1) | O(1) | Remove from top |
| peek() | O(1) | O(1) | View top element |
| isEmpty() | O(1) | O(1) | Check if empty |
All operations are O(1) because they only access the top element. Overall space complexity is O(n) for n elements.
Implementation#
Array-based: Fixed/dynamic array with top pointer - good cache locality
Linked List: Head as top - true dynamic sizing, pointer overhead
Built-ins: Use language-provided implementations (queues, deques) for best performance
// Deque provides efficient stack operations
import 'package:collection/collection.dart';
final stack = DoubleLinkedQueue<String>();
stack.addLast("first"); // O(1)
stack.addLast("second"); // O(1)
String top = stack.last; // O(1)
String popped = stack.removeLast(); // O(1)
bool empty = stack.isEmpty; // O(1)
Example: Balanced Parentheses#
Uses LIFO property to match opening/closing brackets. Push opening brackets, pop when finding closing brackets.
public static boolean isBalanced(String s) {
Stack<Character> stack = new Stack<>();
for (char ch : s.toCharArray()) {
if (ch == '(' || ch == '[' || ch == '{') {
stack.push(ch);
} else if (ch == ')' || ch == ']' || ch == '}') {
if (stack.isEmpty()) return false;
char open = stack.pop();
if ((ch == ')' && open != '(') ||
(ch == ']' && open != '[') ||
(ch == '}' && open != '{')) {
return false;
}
}
}
return stack.isEmpty();
}
import java.util.Stack
fun isBalanced(s: String): Boolean {
val stack = Stack<Char>()
val pairs = mapOf(')' to '(', ']' to '[', '}' to '{')
for (ch in s) {
when (ch) {
'(', '[', '{' -> stack.push(ch)
')', ']', '}' -> {
if (stack.isEmpty() || stack.pop() != pairs[ch]) {
return false
}
}
}
}
return stack.isEmpty()
}
import { Stack } from '@datastructures-js/stack';
function isBalanced(s: string): boolean {
const stack = new Stack<string>();
const pairs: Record<string, string> = {')': '(', ']': '[', '}': '{'};
for (const ch of s) {
if (ch === '(' || ch === '[' || ch === '{') {
stack.push(ch);
} else if (ch === ')' || ch === ']' || ch === '}') {
if (stack.isEmpty() || stack.pop() !== pairs[ch]) {
return false;
}
}
}
return stack.isEmpty();
}
import 'package:collection/collection.dart';
bool isBalanced(String s) {
final stack = DoubleLinkedQueue<String>();
Map<String, String> pairs = {')': '(', ']': '[', '}': '{'};
for (int i = 0; i < s.length; i++) {
String ch = s[i];
if (ch == '(' || ch == '[' || ch == '{') {
stack.addLast(ch);
} else if (ch == ')' || ch == ']' || ch == '}') {
if (stack.isEmpty || stack.removeLast() != pairs[ch]) {
return false;
}
}
}
return stack.isEmpty;
}
import Collections
func isBalanced(_ s: String) -> Bool {
var stack = Deque<Character>()
let pairs: [Character: Character] = [')': '(', ']': '[', '}': '{']
for ch in s {
if ch == '(' || ch == '[' || ch == '{' {
stack.append(ch)
} else if ch == ')' || ch == ']' || ch == '}' {
if stack.isEmpty || stack.removeLast() != pairs[ch] {
return false
}
}
}
return stack.isEmpty
}