Master the max-heap with complete implementation — insert with sift-up, extract maximum with sift-down, Python workaround using negation, in-place heap sort, max-heap for sliding window maximum, and the kth largest element problem.
Max-Heap Property
In a max-heap, every parent is ≥ its children. The maximum element is always at the root.
Max-heap: 50
/ \
30 40
/ \ / \
10 20 35 25
Array: [50, 30, 40, 10, 20, 35, 25]
Python's heapq is Min-Heap — Max-Heap Workaround
Python only provides min-heap. Use negation to simulate max-heap:
import heapq
# Max-heap using negation
max_heap = []
for val in [3, 1, 4, 1, 5, 9, 2, 6]:
heapq.heappush(max_heap, -val) # Negate
# Extract maximum
max_val = -heapq.heappop(max_heap) # Negate back: 9
print(max_val) # 9
# For tuples: negate only the priority field
tasks = []
heapq.heappush(tasks, (-10, "critical")) # High priority = 10
heapq.heappush(tasks, (-5, "medium"))
heapq.heappush(tasks, (-1, "low"))
priority, task = heapq.heappop(tasks)
print(f"{task} (priority {-priority})") # critical (priority 10)
In-Place Heap Sort Using Max-Heap
def heap_sort(arr):
"""
Sort in ascending order using max-heap in-place.
Phase 1: Build max-heap from arr — O(n)
Phase 2: Extract max n times, placing at end — O(n log n)
Total: O(n log n), Space: O(1)
"""
n = len(arr)
def sift_down(heap, n, i):
while True:
largest = i
l, r = 2*i+1, 2*i+2
if l < n and heap[l] > heap[largest]: largest = l
if r < n and heap[r] > heap[largest]: largest = r
if largest != i:
heap[i], heap[largest] = heap[largest], heap[i]
i = largest
else: break
# Phase 1: Build max-heap
for i in range(n // 2 - 1, -1, -1):
sift_down(arr, n, i)
# Phase 2: Extract max n-1 times
for i in range(n - 1, 0, -1):
arr[0], arr[i] = arr[i], arr[0] # Max to end
sift_down(arr, i, 0) # Restore heap on reduced array
return arr
print(heap_sort([12, 11, 13, 5, 6, 7]))
# [5, 6, 7, 11, 12, 13]
Application — Kth Largest Element
import heapq
def find_kth_largest(nums, k):
"""
Find kth largest in O(n log k) using min-heap of size k.
The min-heap of size k contains the k largest elements seen.
Its minimum (root) is the kth largest overall.
"""
min_heap = [] # Min-heap of size k
for num in nums:
heapq.heappush(min_heap, num)
if len(min_heap) > k:
heapq.heappop(min_heap) # Remove smallest → keep k largest
return min_heap[0] # Root of min-heap = kth largest
print(find_kth_largest([3,2,1,5,6,4], 2)) # 5 (2nd largest)
print(find_kth_largest([3,2,3,1,2,4,5,5,6], 4)) # 4 (4th largest)
Application — Sliding Window Maximum
from collections import deque
def sliding_window_max(nums, k):
"""
Find max in each window of size k.
Monotonic decreasing deque. O(n).
"""
result = []
dq = deque() # Indices
for i in range(len(nums)):
while dq and dq[0] < i - k + 1:
dq.popleft()
while dq and nums[dq[-1]] < nums[i]:
dq.pop()
dq.append(i)
if i >= k - 1:
result.append(nums[dq[0]])
return result
print(sliding_window_max([1,3,-1,-3,5,3,6,7], 3))
# [3, 3, 5, 5, 6, 7]
Min vs Max Heap Summary
| Feature | Min-Heap | Max-Heap |
|---|
| Root | Minimum element | Maximum element |
| Heap property | parent ≤ children | parent ≥ children |
| Extract | O(log n) minimum | O(log n) maximum |
| Python built-in | heapq (direct) | heapq with negation |
| Use for | Dijkstra, top-K smallest | Heap sort, top-K largest |
*Next Lesson: Heap Operations*