Heap (Priority Queue)
Heap is a specialized complete binary tree data structure that satisfies the heap property, designed for efficient retrieval of the maximum or minimum element. It is commonly used to implement a priority queue—a data structure where elements are processed based on their priority (not insertion order). Heaps are foundational for algorithms like Heap Sort, Dijkstra’s, and Prim’s MST.
There are two primary types of heaps:
- Max-Heap: The value of each parent node is greater than or equal to the values of its children. The root node is the maximum element in the heap.
- Min-Heap: The value of each parent node is less than or equal to the values of its children. The root node is the minimum element in the heap.
Core Concepts & Properties
1. Complete Binary Tree
A complete binary tree is a tree where all levels are fully filled except possibly the last level, which is filled from left to right. This property allows heaps to be efficiently stored in arrays (no wasted space), with parent-child relationships determined by indices:
- For a node at index
i(0-based array):- Left child:
2i + 1 - Right child:
2i + 2 - Parent:
(i - 1) // 2(integer division)
- Left child:
2. Heap Property
- Max-Heap:
heap[parent(i)] ≥ heap[left(i)]andheap[parent(i)] ≥ heap[right(i)] - Min-Heap:
heap[parent(i)] ≤ heap[left(i)]andheap[parent(i)] ≤ heap[right(i)]
Example Max-Heap (Array Representation)
plaintext
Heap Tree Structure: Array Representation (0-based):
100 (root) [100, 80, 90, 70, 60, 40, 50, 30]
/ \
80 90
/ \ / \
70 60 40 50
/
30
Parent-Child Indices:
- Node 100 (i=0) → Left (i=1:80), Right (i=2:90)
- Node 80 (i=1) → Left (i=3:70), Right (i=4:60)
- Node 90 (i=2) → Left (i=5:40), Right (i=6:50)
- Node 70 (i=3) → Left (i=7:30), Right (i=8: None)
Key Operations
Heaps support 4 core operations, all optimized to maintain the heap property:
- Insert: Add a new element to the heap (O(log n)).
- Extract Max/Min: Remove and return the root element (maximum in Max-Heap, minimum in Min-Heap) (O(log n)).
- Heapify: Convert an unordered array into a heap (O(n)).
- Peek: Return the root element without removing it (O(1)).
Critical Sub-Operations
To maintain the heap property during insert/extract, two helper operations are used:
- Bubble Up (Heapify Up): Move a node up the tree to its correct position (used in
insert). - Bubble Down (Heapify Down): Move a node down the tree to its correct position (used in
extractandheapify).
Heap Implementation (Python)
We’ll implement a Max-Heap (easily modifiable to Min-Heap by reversing the comparison logic). The implementation uses a list to store the heap and includes all core operations.
Full Implementation
python
运行
class MaxHeap:
def __init__(self):
self.heap = [] # Array to store the heap
# -------------------------- Helper Methods --------------------------
def _parent(self, index):
"""Return the index of the parent node."""
return (index - 1) // 2
def _left_child(self, index):
"""Return the index of the left child node."""
return 2 * index + 1
def _right_child(self, index):
"""Return the index of the right child node."""
return 2 * index + 2
def _swap(self, i, j):
"""Swap elements at indices i and j."""
self.heap[i], self.heap[j] = self.heap[j], self.heap[i]
# -------------------------- Bubble Up (Heapify Up) --------------------------
def _bubble_up(self, index):
"""Move the node at 'index' up to its correct position to maintain Max-Heap property."""
parent_idx = self._parent(index)
# While node is not root and parent value < current node value (violates Max-Heap)
while index > 0 and self.heap[parent_idx] < self.heap[index]:
self._swap(parent_idx, index)
index = parent_idx
parent_idx = self._parent(index)
# -------------------------- Bubble Down (Heapify Down) --------------------------
def _bubble_down(self, index):
"""Move the node at 'index' down to its correct position to maintain Max-Heap property."""
n = len(self.heap)
while True:
left_idx = self._left_child(index)
right_idx = self._right_child(index)
largest_idx = index # Assume current node is the largest
# Check if left child exists and is larger than current largest
if left_idx < n and self.heap[left_idx] > self.heap[largest_idx]:
largest_idx = left_idx
# Check if right child exists and is larger than current largest
if right_idx < n and self.heap[right_idx] > self.heap[largest_idx]:
largest_idx = right_idx
# If current node is already the largest, heap property is restored
if largest_idx == index:
break
# Swap current node with the largest child and continue bubbling down
self._swap(index, largest_idx)
index = largest_idx
# -------------------------- Core Operations --------------------------
def insert(self, value):
"""Insert a new value into the heap."""
# Add value to the end of the heap (maintains complete binary tree property)
self.heap.append(value)
# Bubble up to restore Max-Heap property
self._bubble_up(len(self.heap) - 1)
def extract_max(self):
"""Remove and return the maximum value (root) from the heap. Return None if heap is empty."""
if not self.heap:
return None
n = len(self.heap)
# Swap root (max) with the last element (maintains complete binary tree)
self._swap(0, n - 1)
# Remove the max value from the end of the heap
max_value = self.heap.pop()
# Bubble down the new root to restore Max-Heap property
self._bubble_down(0)
return max_value
def peek_max(self):
"""Return the maximum value (root) without removing it. Return None if heap is empty."""
return self.heap[0] if self.heap else None
def heapify(self, arr):
"""Convert an unordered array into a Max-Heap (in-place)."""
self.heap = arr.copy()
n = len(self.heap)
# Start heapifying from the last non-leaf node (all leaf nodes are already heaps)
# Last non-leaf node index: (n // 2) - 1
for i in range(n // 2 - 1, -1, -1):
self._bubble_down(i)
def is_empty(self):
"""Check if the heap is empty."""
return len(self.heap) == 0
def size(self):
"""Return the number of elements in the heap."""
return len(self.heap)
# Test the MaxHeap implementation
if __name__ == "__main__":
# Initialize MaxHeap
max_heap = MaxHeap()
# Insert elements
values = [30, 70, 80, 100, 60, 40, 90, 50]
for val in values:
max_heap.insert(val)
print("Heap after insertions:", max_heap.heap) # Output: [100, 80, 90, 70, 60, 40, 30, 50]
# Peek max
print("Peek max:", max_heap.peek_max()) # Output: 100
# Extract max
print("\nExtracting max values:")
while not max_heap.is_empty():
print(max_heap.extract_max(), end=" ") # Output: 100 90 80 70 60 50 40 30
print()
# Heapify an unordered array
unordered_arr = [5, 3, 8, 1, 2, 9, 4]
max_heap.heapify(unordered_arr)
print("\nHeap after heapifying [5,3,8,1,2,9,4]:", max_heap.heap) # Output: [9, 3, 8, 1, 2, 5, 4]
Min-Heap Modification
To convert the Max-Heap to a Min-Heap, reverse the comparison logic in _bubble_up and _bubble_down:
- In
_bubble_up: Changeself.heap[parent_idx] < self.heap[index]toself.heap[parent_idx] > self.heap[index]. - In
_bubble_down: Changeself.heap[left_idx] > self.heap[largest_idx]toself.heap[left_idx] < self.heap[smallest_idx](and similarly for the right child).
Time and Space Complexity
| Operation | Time Complexity | Explanation |
|---|---|---|
| Insert | O(log n) | Bubble up traverses the height of the heap (height of complete binary tree = log n). |
| Extract Max/Min | O(log n) | Bubble down traverses the height of the heap. |
| Heapify | O(n) | Contrary to intuition—heapifying from the last non-leaf node takes linear time (mathematically proven). |
| Peek | O(1) | Direct access to the root element (index 0). |
| Size/Is Empty | O(1) | Directly check the length of the heap array. |
| Space Complexity | O(n) | Stores n elements in the heap array (no extra space for tree structure—uses array indices). |
Pros and Cons of Heaps
Pros
- Efficient Extremum Retrieval: Extracting the max/min element is O(log n) (far faster than arrays (O(n)) or unsorted lists (O(n))).
- Priority Queue Implementation: The de facto standard for priority queues (critical for Dijkstra’s, Prim’s, and Huffman Coding).
- In-Place Heap Sort: Heapify enables an efficient O(n log n) sorting algorithm with O(1) auxiliary space.
- Complete Binary Tree Efficiency: Stored as an array with no wasted space (unlike linked trees).
Cons
- No Random Access: Cannot efficiently access arbitrary elements (only the root is accessible in O(1) time).
- No Ordered Traversal: Heaps do not maintain elements in sorted order (only the heap property)—sorted traversal requires extracting elements one by one (O(n log n)).
- Slow for Non-Extremum Operations: Finding or deleting an arbitrary element is O(n) (must scan the entire array).
- Fixed Heap Type: A Max-Heap cannot efficiently retrieve the minimum element (and vice versa) without extra logic.
Real-World Applications of Heaps
- Priority Queues: Task scheduling (e.g., operating systems prioritizing high-priority processes), job queues (e.g., print spoolers), and event-driven simulations (e.g., processing events in time order).
- Sorting: Heap Sort (O(n log n) time, O(1) space) — useful for memory-constrained environments.
- Graph Algorithms: Dijkstra’s shortest path algorithm (uses a min-heap to track the next node with the smallest tentative distance) and Prim’s MST algorithm (uses a min-heap to track the next edge with the smallest weight).
- Data Streaming: Finding the k largest/smallest elements in a stream (e.g., top 10 trending topics on Twitter) using a min-heap/max-heap of size k (O(n log k) time).
- Huffman Coding: Compression algorithms use heaps to build optimal prefix codes.
- Median Maintenance: Maintaining the median of a dynamic dataset using two heaps (max-heap for lower half, min-heap for upper half).
Heap vs. Other Data Structures (Key Differences)
| Feature | Heap | Array (Sorted) | Hash Table | Binary Search Tree (Balanced) |
|---|---|---|---|---|
| Extract Max/Min | O(log n) | O(1) (last/first element) | O(n) (must scan all elements) | O(log n) (max: rightmost node) |
| Insert | O(log n) | O(n) (shift elements) | O(1) (average case) | O(log n) |
| Search Arbitrary Element | O(n) | O(log n) (binary search) | O(1) (average case) | O(log n) |
| Sorted Traversal | O(n log n) (extract all) | O(n) (direct traversal) | O(n log n) (sort first) | O(n) (in-order traversal) |
Summary
Weaknesses: No random access, no sorted traversal, slow arbitrary element operations.
A Heap is a complete binary tree with the max/min-heap property, stored as an array for efficiency.
Core operations: Insert (O(log n)), Extract Max/Min (O(log n)), Heapify (O(n)), Peek (O(1)).
Key use case: Implementing priority queues for algorithms and scheduling.
Strengths: Fast extremum retrieval, efficient priority-based processing, low space overhead.
- iPhone 15 Pro Review: Ultimate Features and Specs
- iPhone 15 Pro Max: Key Features and Specifications
- iPhone 16: Features, Specs, and Innovations
- iPhone 16 Plus: Key Features & Specs
- iPhone 16 Pro: Premium Features & Specs Explained
- iPhone 16 Pro Max: Features & Innovations Explained
- iPhone 17 Pro: Features and Innovations Explained
- iPhone 17 Review: Features, Specs, and Innovations
- iPhone Air Concept: Mid-Range Power & Portability
- iPhone 13 Pro Max Review: Features, Specs & Performance
- iPhone SE Review: Budget Performance Unpacked
- iPhone 14 Review: Key Features and Upgrades
- Apple iPhone 14 Plus: The Ultimate Mid-range 5G Smartphone
- iPhone 14 Pro: Key Features and Innovations Explained
- Why the iPhone 14 Pro Max Redefines Smartphone Technology
- iPhone 15 Review: Key Features and Specs
- iPhone 15 Plus: Key Features and Specs Explained
- iPhone 12 Mini Review: Compact Powerhouse Unleashed
- iPhone 12: Key Features and Specs Unveiled
- iPhone 12 Pro: Premium Features and 5G Connectivity
- Why the iPhone 12 Pro Max is a Top Choice in 2023
- iPhone 13 Mini: Compact Powerhouse in Your Hand
- iPhone 13: Key Features and Specs Overview
- iPhone 13 Pro Review: Features and Specifications






















Leave a comment