Median of Data Stream Using Two Heaps in DSA C++ - Time & Space Complexity
We want to understand how fast we can find the middle value when numbers keep coming in one by one.
How does the time needed grow as more numbers arrive?
Analyze the time complexity of the following code snippet.
#include <queue>
#include <vector>
std::priority_queue<int> maxHeap; // stores smaller half
std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap; // stores larger half
void addNum(int num) {
if (maxHeap.empty() || num <= maxHeap.top()) maxHeap.push(num);
else minHeap.push(num);
if (maxHeap.size() > minHeap.size() + 1) {
minHeap.push(maxHeap.top()); maxHeap.pop();
} else if (minHeap.size() > maxHeap.size()) {
maxHeap.push(minHeap.top()); minHeap.pop();
}
}
double findMedian() {
if (maxHeap.size() > minHeap.size()) return maxHeap.top();
return (maxHeap.top() + minHeap.top()) / 2.0;
}
This code keeps two heaps to quickly find the median as new numbers come in.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Inserting a number into one of the two heaps and balancing them.
- How many times: Each insertion happens once per new number added.
Each new number causes one insertion and possibly one balancing move between heaps.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 insertions and up to 10 balancing moves |
| 100 | About 100 insertions and up to 100 balancing moves |
| 1000 | About 1000 insertions and up to 1000 balancing moves |
Pattern observation: The number of operations grows roughly in a straight line with the number of inputs.
Time Complexity: O(n log n)
This means that adding n numbers and keeping track of the median takes time that grows a bit faster than n, because each insertion into a heap takes some extra steps.
[X] Wrong: "Adding a number and finding the median is always O(1) because heaps are fast."
[OK] Correct: Each insertion into a heap takes time proportional to the height of the heap, which grows with the number of elements, so it is not constant time.
Understanding how to keep track of medians efficiently shows your skill in using data structures smartly to handle changing data.
"What if we used a balanced binary search tree instead of two heaps? How would the time complexity change?"
Practice
Solution
Step 1: Understand the role of two heaps
The max-heap stores the smaller half of the numbers, and the min-heap stores the larger half.Step 2: Explain how median is found
Balancing these heaps allows quick access to the middle values, enabling efficient median calculation.Final Answer:
To efficiently find the median by balancing smaller and larger halves of the data -> Option AQuick Check:
Two heaps balance halves = median found fast [OK]
- Thinking heaps sort entire data
- Using one heap only
- Confusing heaps with arrays
priority_queue?Solution
Step 1: Recall default priority_queue behavior
By default,priority_queuein C++ is a max-heap usingless<int>.Step 2: Identify correct declaration
Declaringpriority_queue<int> maxHeap;creates a max-heap without extra parameters.Final Answer:
priority_queue<int> maxHeap; -> Option BQuick Check:
Default priority_queue = max-heap [OK]
- Using greater<int> for max-heap
- Omitting vector container
- Confusing max-heap with min-heap syntax
priority_queue<int> maxHeap;
priority_queue minHeap;
// Insert 10
maxHeap.push(10);
// Insert 20
minHeap.push(20);
// Insert 15
if (15 <= maxHeap.top()) maxHeap.push(15); else minHeap.push(15);
// Balance heaps
if (maxHeap.size() > minHeap.size() + 1) {
minHeap.push(maxHeap.top());
maxHeap.pop();
} else if (minHeap.size() > maxHeap.size()) {
maxHeap.push(minHeap.top());
minHeap.pop();
}
// Calculate median
if (maxHeap.size() == minHeap.size())
cout << (maxHeap.top() + minHeap.top()) / 2.0 << endl;
else
cout << maxHeap.top() << endl;What is the output of this code?Solution
Step 1: Insert elements and balance heaps
Insert 10 into maxHeap: maxHeap = [10]. Insert 20 into minHeap: minHeap = [20]. Insert 15: 15 > 10, so goes to minHeap: minHeap = [15, 20]. Balance heaps: minHeap size (2) > maxHeap size (1), so move minHeap top (15) to maxHeap. Now maxHeap = [15, 10], minHeap = [20].Step 2: Calculate median
maxHeap size = 2, minHeap size = 1, so median is maxHeap.top() = 15. Sizes unequal, cout << maxHeap.top() << endl; outputs 15.Final Answer:
15 -> Option AQuick Check:
Median after balancing = 15 [OK]
- Not balancing heaps correctly
- Integer division instead of float
- Wrong heap insertion condition
priority_queue<int> maxHeap;
priority_queue minHeap;
void addNumber(int num) {
if (maxHeap.empty() || num <= maxHeap.top()) {
maxHeap.push(num);
} else {
minHeap.push(num);
}
if (maxHeap.size() > minHeap.size()) {
minHeap.push(maxHeap.top());
maxHeap.pop();
} else if (minHeap.size() > maxHeap.size() + 1) {
maxHeap.push(minHeap.top());
minHeap.pop();
}
}Solution
Step 1: Analyze balancing conditions
The code moves element from maxHeap to minHeap if maxHeap.size() > minHeap.size(), but it should only do so if maxHeap.size() > minHeap.size() + 1 to keep heaps balanced properly.Step 2: Confirm correct balancing logic
Proper balancing ensures size difference is at most 1. The current condition causes unnecessary moves, breaking balance.Final Answer:
The balancing condition for maxHeap is incorrect; it should check if maxHeap.size() > minHeap.size() + 1 -> Option CQuick Check:
Balance heaps only if size difference > 1 [OK]
- Wrong balancing condition
- Swapping heap roles
- Incorrect comparison operators
Solution
Step 1: Insert elements and balance heaps step-by-step
After processing the entire stream with proper insertion (to maxHeap if <= max.top or empty, else minHeap) and balancing (rebalance if max.size > min.size + 1 or min.size > max.size), final state: maxHeap size=5 (top=7), minHeap size=5 (top=8).Step 2: Calculate final median
After all insertions, maxHeap size = 5, minHeap size = 5, median = average of tops: (7 + 8) / 2 = 7.5Final Answer:
7.5 -> Option DQuick Check:
Median after all insertions = 7.5 [OK]
- Not balancing heaps after each insertion
- Calculating median from wrong heap
- Forgetting to average when heaps equal size
Ready to prove it?
Pass the test and this pattern moves unknown
