题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
实例输出
随着数据流的增加,不断的更新中位数,并输出
分析
根据时间效率表发现,用二叉树、AVL数、最大堆和最小堆的效率最高,但由于二叉树和AVL数没有现成的数据结构,所以最终决定用最大堆和最小堆实现。
思路
- 用min堆实现左边的的数据容器,max堆实现右边的数据容器。
- 中位数永远放在第一个位置,如果奇数个就直接取min[0],如果偶数就是min[0]和max[0]的平均数
- 当前size为奇数则存入max,偶数存入min
- 两堆大小之差不能超过1
由实例输出可得
5 -> 5 -------------------------------------(min[0] = 5)
5,2 -> (5+2)/2 = 3.5------------------- (min[0] = 5, max[0] = 2)
5,2,3 -> 3-------------------------------- (min[0] = 3, min[1] = 5, max[0] = 2)
5,2,3,4 -> (3+4)/2 = 3.5-------------- ( min[0] = 3, min[1] = 5, max[0] = 4, max[1] = 2)
代码
class Solution {
public:
void Insert(int num)
{
//even : save num in to min[]
if(((min.size() + max.size()) & 1 )== 0 ){
if(min.size() > 0 && num < max[0]){
max.push_back(num);
// big -> small
push_heap(max.begin(), max.end(),less<int>());
num = max[0];
pop_heap(max.begin(), max.end(), less<int>());
max.pop_back();
}
min.push_back(num);
// order heap : small -> big
push_heap(min.begin(), min.end(), greater<int>());
}
//odd : save num in to max[]
else {
if(min.size() > 0 && num > min[0]){
min.push_back(num);
push_heap(min.begin(),min.end(),greater<int>());
num = min[0];
pop_heap(min.begin(),min.end(),greater<int>());
min.pop_back();
}
max.push_back(num);
push_heap(max.begin(), max.end(), less<int>());
}
}
double GetMedian()
{
int size = min.size() + max.size();
if( size == 0) return 0;
// even
if( size & 1 == 0) {
return (min[0] + max[0])/2.0;
}
else {
return min[0];
}
}
private:
vector<int> min;
vector<int> max;
};
关于最大堆和最小堆
Heap in C++ STL
make_heap() : 将数组转成堆形式
vector<int> v1 = {20, 30, 40, 25, 15};
make_heap(v1.begin(), v1.end());
push_heap() : 往堆中加新的元素
pop_heap() : 删除堆中最大的元素
//INSERT
//从大到小
push_heap(v1.begin(), v1.end());
push_heap(v1.begin(),v1.end(),less<int>());
cout << v1.front();
//从小到大
push_heap(v1.begin(),v1.end(),greater<int>());
//DELETE
pop_heap(v1.begin(), v1.end());
v1.pop_back();
sort_heap() : 排序堆,但排序后不再是堆的形式,默认从小到大
// 创建向量
vector<int> v1 = {20, 30, 40, 25, 15};
// 转为堆形式
make_heap(v1.begin(), v1.end());
// 输出堆
cout << "The heap elements are : ";
for (int &x : v1)
cout << x << " ";
cout << endl;
//排序
sort_heap(v1.begin(), v1.end());
// 输出堆
cout << "The heap elements after sorting are : ";
for (int &x : v1)
cout << x << " ";
output:
The heap elements are : 40 30 20 25 15
The heap elements after sorting are : 15 20 25 30 40
is_heap() : 判断是否是堆,返回true/false
is_heap(v1.begin(), v1.end())?
cout << "The container is heap ":
cout << "The container is not heap";
cout << endl;
is_heap_until() :返回位置
// 确认当前位置
// till which container is heap
auto it = is_heap_until(v1.begin(), v1.end());