Spaces:
Sleeping
Sleeping
| STACK AND QUEUE | |
| =============== | |
| --- STACK --- | |
| LIFO — Last In First Out. Think of a stack of plates. | |
| Operations: push (add), pop (remove top), peek (view top). All O(1). | |
| Uses: undo/redo, function call stack, expression evaluation, DFS, balanced brackets. | |
| # Stack using Python list | |
| class Stack: | |
| def __init__(self): | |
| self.items = [] | |
| def push(self, item): | |
| self.items.append(item) | |
| def pop(self): | |
| if self.is_empty(): | |
| raise IndexError("Stack is empty") | |
| return self.items.pop() | |
| def peek(self): | |
| if self.is_empty(): | |
| raise IndexError("Stack is empty") | |
| return self.items[-1] | |
| def is_empty(self): | |
| return len(self.items) == 0 | |
| def size(self): | |
| return len(self.items) | |
| s = Stack() | |
| s.push(10) | |
| s.push(20) | |
| s.push(30) | |
| print(s.peek()) # 30 | |
| print(s.pop()) # 30 | |
| print(s.size()) # 2 | |
| --- Balanced Brackets using Stack --- | |
| Check if brackets (, ), {, }, [, ] are balanced. | |
| def is_balanced(expr): | |
| stack = [] | |
| pairs = {')': '(', '}': '{', ']': '['} | |
| for ch in expr: | |
| 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 | |
| print(is_balanced("({[]})")) # True | |
| print(is_balanced("({[})")) # False | |
| print(is_balanced("((()))")) # True | |
| --- Next Greater Element using Stack --- | |
| For each element, find the next element greater than it. | |
| Time: O(n). Space: O(n). | |
| def next_greater(arr): | |
| n = len(arr) | |
| result = [-1] * n | |
| stack = [] # stores indices | |
| for i in range(n): | |
| while stack and arr[stack[-1]] < arr[i]: | |
| result[stack.pop()] = arr[i] | |
| stack.append(i) | |
| return result | |
| print(next_greater([4, 5, 2, 25])) # [5, 25, 25, -1] | |
| --- Evaluate Postfix Expression --- | |
| Postfix: operands come before operator (e.g. "2 3 +" = 5). | |
| def evaluate_postfix(expression): | |
| stack = [] | |
| for token in expression.split(): | |
| if token.lstrip('-').isdigit(): | |
| stack.append(int(token)) | |
| else: | |
| b = stack.pop() | |
| a = stack.pop() | |
| if token == '+': stack.append(a + b) | |
| elif token == '-': stack.append(a - b) | |
| elif token == '*': stack.append(a * b) | |
| elif token == '/': stack.append(int(a / b)) | |
| return stack[0] | |
| print(evaluate_postfix("2 3 1 * + 9 -")) # Output: -4 | |
| --- Min Stack --- | |
| Stack that supports getMin() in O(1). | |
| class MinStack: | |
| def __init__(self): | |
| self.stack = [] | |
| self.min_stack = [] | |
| def push(self, val): | |
| self.stack.append(val) | |
| if not self.min_stack or val <= self.min_stack[-1]: | |
| self.min_stack.append(val) | |
| def pop(self): | |
| val = self.stack.pop() | |
| if val == self.min_stack[-1]: | |
| self.min_stack.pop() | |
| def get_min(self): | |
| return self.min_stack[-1] | |
| ms = MinStack() | |
| ms.push(5); ms.push(3); ms.push(7); ms.push(2) | |
| print(ms.get_min()) # 2 | |
| ms.pop() | |
| print(ms.get_min()) # 3 | |
| --- QUEUE --- | |
| FIFO — First In First Out. Think of a line at a ticket counter. | |
| Operations: enqueue (add rear), dequeue (remove front), peek. All O(1). | |
| Uses: BFS, scheduling, print queues, sliding window. | |
| from collections import deque | |
| class Queue: | |
| def __init__(self): | |
| self.items = deque() | |
| def enqueue(self, item): | |
| self.items.append(item) | |
| def dequeue(self): | |
| if self.is_empty(): | |
| raise IndexError("Queue is empty") | |
| return self.items.popleft() | |
| def peek(self): | |
| return self.items[0] | |
| def is_empty(self): | |
| return len(self.items) == 0 | |
| def size(self): | |
| return len(self.items) | |
| q = Queue() | |
| q.enqueue(10) | |
| q.enqueue(20) | |
| q.enqueue(30) | |
| print(q.dequeue()) # 10 | |
| print(q.peek()) # 20 | |
| --- Circular Queue --- | |
| Fixed-size queue where rear wraps around to front. | |
| class CircularQueue: | |
| def __init__(self, capacity): | |
| self.queue = [None] * capacity | |
| self.front = self.rear = -1 | |
| self.capacity = capacity | |
| self.size = 0 | |
| def enqueue(self, item): | |
| if self.size == self.capacity: | |
| raise OverflowError("Queue is full") | |
| self.rear = (self.rear + 1) % self.capacity | |
| self.queue[self.rear] = item | |
| if self.front == -1: | |
| self.front = 0 | |
| self.size += 1 | |
| def dequeue(self): | |
| if self.size == 0: | |
| raise IndexError("Queue is empty") | |
| item = self.queue[self.front] | |
| self.front = (self.front + 1) % self.capacity | |
| self.size -= 1 | |
| return item | |
| --- Deque (Double-Ended Queue) --- | |
| Insert and delete from both ends in O(1). | |
| from collections import deque | |
| d = deque() | |
| d.appendleft(1) # add to front | |
| d.append(2) # add to rear | |
| d.appendleft(0) | |
| print(d) # deque([0, 1, 2]) | |
| d.popleft() # remove from front → 0 | |
| d.pop() # remove from rear → 2 | |
| print(d) # deque([1]) | |
| --- Priority Queue --- | |
| Elements are dequeued based on priority, not insertion order. | |
| Python's heapq is a min-heap by default. | |
| import heapq | |
| pq = [] | |
| heapq.heappush(pq, (3, 'low')) | |
| heapq.heappush(pq, (1, 'high')) | |
| heapq.heappush(pq, (2, 'medium')) | |
| print(heapq.heappop(pq)) # (1, 'high') | |
| print(heapq.heappop(pq)) # (2, 'medium') | |
| # Max-heap: negate priorities | |
| heapq.heappush(pq, (-5, 'top priority')) | |
| print(heapq.heappop(pq)) # (-5, 'top priority') | |
| --- Difference: Stack vs Queue --- | |
| Stack: LIFO — last added is first removed. Uses: DFS, backtracking, undo. | |
| Queue: FIFO — first added is first removed. Uses: BFS, scheduling, buffering. | |