📑 Table of Contents
1. Introduction to Collections
A collection is a data type that stores groups of items. Different collections have different key operations and are implemented with different data structures.
Common Collections
| Data Type | Key Operations | Data Structure |
|---|---|---|
| Stack | PUSH, POP | Linked list, resizing array |
| Queue | ENQUEUE, DEQUEUE | Linked list, resizing array |
| Priority Queue | INSERT, DELETE-MAX | Binary heap |
| Symbol Table | PUT, GET, DELETE | BST, hash table |
| Set | ADD, CONTAINS, DELETE | BST, hash table |
2. Priority Queue ADT
Definition
A Priority Queue is a collection where you insert and delete items, but unlike a regular queue, you remove the largest (or smallest) item, not the item that was added first or last.
Key Differences from Other Collections
- Stack: Remove the item most recently added (LIFO)
- Queue: Remove the item least recently added (FIFO)
- Randomized Queue: Remove a random item
- Priority Queue: Remove the largest (or smallest) item
Priority Queue API (Java)
Key must implement Comparable<Key> so that items can be ordered.
Example Operations
Example: Priority Queue Operations
| Operation | Argument | Return Value | Contents (unordered) |
|---|---|---|---|
| insert | P | - | P |
| insert | Q | - | P Q |
| insert | E | - | P Q E |
| removeMax | - | Q | P E |
| insert | X | - | P E X |
| insert | A | - | P E X A |
| insert | M | - | P E X A M |
| removeMax | - | X | P E M A |
3. Priority Queue Applications
Priority queues generalize stacks, queues, and randomized queues, and have numerous real-world applications:
🌟 Real-World Applications
- Event-driven simulation: Customers in a line, colliding particles
- Numerical computation: Reducing roundoff error
- Data compression: Huffman codes
- Graph searching: Dijkstra's algorithm, Prim's algorithm
- Number theory: Sum of powers
- Artificial intelligence: A* search
- Statistics: Online median in data stream
- Operating systems: Load balancing, interrupt handling
- Computer networks: Web cache
- Discrete optimization: Bin packing, scheduling
- Spam filtering: Bayesian spam filter
4. Complete Binary Trees
Binary Tree
A binary tree is either empty or a node with links to left and right binary trees (each node has at most 2 children).
Complete Binary Tree
A complete tree is perfectly balanced, except possibly for the bottom level. All levels are completely filled except possibly the last level, which is filled from left to right.
Complete Binary Tree Example (N = 16, height = 4)
○
/ \
○ ○
/ \ / \
○ ○ ○ ○
/\\/\\/\\/\
○○○○○○○○○
📐 Important Property
Height of a complete tree with N nodes is ⌊lg N⌋
The height increases only when N is a power of 2.
This logarithmic height is what makes heaps efficient!
Why Complete Binary Trees?
✅ Advantages
- Guaranteed logarithmic height
- Can be stored efficiently in an array
- No explicit links needed
- Easy to navigate using array indices
⚠️ Constraints
- Must maintain completeness property
- Insertions must go at the end
- Deletions require restructuring
5. Heap Definition & Properties
Binary Heap
A binary heap is an array representation of a heap-ordered complete binary tree.
Two Key Properties
1. Heap-Order Property
For every internal node v other than the root:
key(v) ≥ key(parent(v))
This means: Parent's key is no smaller than children's keys
Or equivalently: Each node's key must be less than or equal to its parent's key.
2. Complete Binary Tree Property
The tree must be a complete binary tree (as defined above).
Types of Heaps
| Heap Type | Property | Root Contains |
|---|---|---|
| Max Heap | Parent ≥ Children | Maximum element |
| Min Heap | Parent ≤ Children | Minimum element |
Array Representation
Array Indices for Navigation
In a heap stored in array a[] starting at index 1:
- Root: a[1]
- Parent of node at k: a[k/2]
- Left child of node at k: a[2k]
- Right child of node at k: a[2k+1]
Heap Visualization (Max Heap)
Tree representation:
T (1)
/ \
S(2) R(3)
/ \ / \
P(4)N(5)O(6)A(7)
/\ /\
E I H G
8 9 10 11
Array representation:
Note: Index 0 is not used (we start at index 1)
🎯 Key Properties
- The largest key is always at
a[1](the root) - We can navigate the tree using simple arithmetic on array indices
- No explicit links (pointers) are needed!
- Space efficient: only need array of size N+1
6. Heap Operations
6.1 Insert Operation (Swim Up)
Insert Algorithm
- Add the new key at the end of the array (position N+1)
- The new node becomes the new "last node" of the complete tree
- Swim up: Compare with parent and swap if necessary
- Repeat until heap order is restored
Swim Helper Method
Insert Method
Example: Insert 'S' into heap
Before: After adding: After swim:
T T S
/ \ / \ / \
P R P R T R
/ \ / \ / / \ /
N H N H S N H P
Heap: T P R N H → T P R N H S → S T R N H P
(violates) (restored)
⏱️ Time Complexity of Insert
At most 1 + lg N compares
Why? In the worst case, we swim from the bottom to the top of the tree, and the height is ⌊lg N⌋.
6.2 Delete Maximum Operation (Sink Down)
Delete Max Algorithm
- Save the root value (maximum) to return later
- Exchange root with the last node (at position N)
- Decrement N (remove last position)
- Sink down: Compare with children and swap with larger child if necessary
- Repeat until heap order is restored
- Return the saved maximum value
Sink Helper Method
Delete Max Method
Example: Delete maximum from heap
Before: After exchange: After sink:
T H S
/ \ / \ / \
S R S R P R
/ \ / \ / \ / / \ /
P N O A P N O A N H O A
Remove T → Exchange with H → Sink H down
(return T) (violates order) (restored)
❓ Why swap with the larger child?
If we swapped with the smaller child, we might end up with a parent smaller than its other child, violating heap order. By swapping with the larger child, we ensure both children will be smaller than the promoted parent.
⏱️ Time Complexity of Delete Max
At most 2 lg N compares
Why 2? At each level, we compare the two children (1 compare) and then compare with parent (1 more compare). Height is ⌊lg N⌋.
7. Complete Java Implementation
- Array indices start at 1 (index 0 is not used)
- For simplicity, this uses fixed capacity (could be made resizing)
- Generic type
Keymust implementComparable - Setting
pq[N+1] = nullprevents loitering (allows garbage collection)
8. Time Complexity Analysis
Elementary Implementations vs Binary Heap
| Implementation | Insert | Delete Max | Get Max |
|---|---|---|---|
| Unordered Array | 1 | N | N |
| Ordered Array | N | 1 | 1 |
| Binary Heap | log N | log N | 1 |
🎯 Why Binary Heap is Optimal
- Logarithmic operations: Both insert and delete max are O(log N)
- Constant time max: Getting the maximum is O(1)
- Space efficient: Only O(N) space needed
- Simple implementation: Just an array with two helper functions
Detailed Analysis
Insert Operation
- Best case: O(1) - element already in correct position
- Worst case: O(log N) - swim from bottom to top
- Average case: O(log N)
Delete Max Operation
- Best case: O(log N) - still need to check children
- Worst case: O(log N) - sink from top to bottom
- Average case: O(log N)
9. Heap Sort
Heapsort Algorithm
Heapsort is a comparison-based sorting algorithm that uses a binary heap to sort an array in O(N log N) time using O(1) extra space.
Algorithm Overview
- Build heap: Rearrange array into a heap
- Sortdown: Repeatedly remove the maximum (root) and place at end
Using Priority Queue for Sorting
Time Complexity
⏱️ Runtime Analysis
- Building heap: O(N log N) with repeated inserts
- Removing all elements: O(N log N)
- Total: O(N log N)
- Space: O(N) for the heap
Comparison with Other Sorts
| Algorithm | Time Complexity | Space | Stable? |
|---|---|---|---|
| Insertion Sort | O(N²) | O(1) | ✅ Yes |
| Selection Sort | O(N²) | O(1) | ❌ No |
| Merge Sort | O(N log N) | O(N) | ✅ Yes |
| Heap Sort | O(N log N) | O(N) | ❌ No |
| Quick Sort | O(N log N)* | O(log N) | ❌ No |
* Average case; worst case is O(N²)
✅ Advantages of Heapsort
- Guaranteed O(N log N) performance
- In-place sorting (no extra array needed)
- No worst-case quadratic behavior
- Simple implementation
⚠️ Disadvantages
- Not stable
- Poor cache performance
- Slower than quicksort in practice
- Not adaptive (doesn't benefit from partial order)
10. Practice Problems & Key Concepts
Practice Problem 1: Build a Max Heap
Problem
Insert the following elements into an empty max heap in order: 2, 5, 16, 4, 10, 23, 39, 18, 26, 15
Solution Steps
The solution requires building up the heap one element at a time, swimming up after each insertion. The final heap should be:
39
/ \
26 23
/ \ / \
18 15 16 5
/ \ /
2 4 10
Array: [-, 39, 26, 23, 18, 15, 16, 5, 2, 4, 10]
Practice Problem 2: Delete Operations
Problem
From the heap above, perform three deleteMax() operations. Show the heap after each deletion.
Hint
Remember: Exchange root with last element, remove last, then sink down.
Practice Problem 3: Is this a Heap?
Problem
Determine if the following binary tree is a valid max heap:
8
/ \
30 12
/ \ / \
60 40 50 60
Answer
NO - The smallest element in a heap should always be found in the root node. Here, 8 is the root but it's smaller than its children (30 and 12), violating the heap-order property.
🎯 Key Concepts to Remember
- Complete Binary Tree: All levels filled except possibly last, which fills left-to-right
- Heap-Order Property: Parent ≥ Children (max heap) or Parent ≤ Children (min heap)
- Array Representation: Parent at k/2, children at 2k and 2k+1
- Root is at index 1: Makes math simpler (parent = k/2)
- Maximum always at root: O(1) access to max element
- Height is ⌊log N⌋: Guarantees logarithmic operations
- Swim up: Used after insert, compares with parent
- Sink down: Used after delete max, compares with larger child
- Both operations: O(log N) time complexity
- No explicit links needed: Array arithmetic handles navigation
📚 Study Tips
- Draw it out: Visualize heap operations by drawing trees
- Trace the code: Follow swim and sink operations step-by-step
- Understand the why: Know why we swap with larger child in sink
- Practice array indexing: Get comfortable with k/2, 2k, 2k+1
- Memorize complexities: Insert O(log N), Delete Max O(log N), Get Max O(1)
- Compare implementations: Understand trade-offs vs other data structures
Common Mistakes to Avoid
- ❌ Starting array at index 0 (makes parent/child math harder)
- ❌ Forgetting to set deleted elements to null (memory leak)
- ❌ Swapping with smaller child in sink (violates heap order)
- ❌ Not checking array bounds in sink
- ❌ Confusing max heap with min heap properties
- ❌ Thinking heap is sorted (it's only partially ordered)