题目
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。
如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
思路
采用大根堆+小根堆结合的方法,且满足:
① 两个堆中的数据数目差不能超过1,这样可以使中位数只会出现在两个堆的交接处;
② 大顶堆的所有数据都小于小顶堆,这样就满足了排序要求。
(左边大顶堆,右边小顶堆)
1、插入的思路:
1)若已读取的个数为偶数(包括0)时,两个堆的数目已经相同,将新读取的数插入到小顶堆中,从而实现小顶堆的个数多一。但是,如果新读取的数字比大顶堆中最大的数字还小,就不能直接插入到小顶堆中了 ,此时必须将新数字插入到大顶堆中,而将大顶堆中的最大数字插入到小顶堆中,从而实现小顶堆的个数多一。
2)若已读取的个数为奇数时,小顶堆的个数多一,所以要将新读取数字插入到大顶堆中,此时方法与上面类似。
2、取中位数的思路:
① 当总个数为偶数时,使两个堆的数目相同,则中位数=大顶堆的最大数字与小顶堆的最小数字的平均值;
② 而总个数为奇数时,使小顶堆的个数比大顶堆多一,则中位数=小顶堆的最小数字。
#include <cstdio>
#include <algorithm>
#include <vector>
#include <functional>
using namespace std;
template<typename T> class DynamicArray
{
public:
void Insert(T num)
{
if(((min.size() + max.size()) & 1) == 0)//保证两个堆的size差<=1,size和为奇数时插进minHeap
{
if(max.size() > 0 && num < max[0])//保证最小堆的数 都大于 最大堆。
{
max.push_back(num);
push_heap(max.begin(), max.end(), less<T>());
num = max[0];
pop_heap(max.begin(), max.end(), less<T>());
max.pop_back();
}
min.push_back(num);
push_heap(min.begin(), min.end(), greater<T>());
}
else
{
if(min.size() > 0 && min[0] < num)
{
min.push_back(num);
push_heap(min.begin(), min.end(), greater<T>());
num = min[0];
pop_heap(min.begin(), min.end(), greater<T>());
min.pop_back();
}
max.push_back(num);
push_heap(max.begin(), max.end(), less<T>());
}
}
T GetMedian()
{
int size = min.size() + max.size();
if(size == 0)
throw exception("No numbers are available");
T median = 0;
if((size & 1) == 1)
median = min[0];
else
median = (min[0] + max[0]) / 2;
return median;
}
private:
vector<T> min;
vector<T> max;
};
关于push_heap和pop_heap的使用
make_heap:根据不同参数生成大顶堆或者小顶堆,默认大顶堆。
make_heap(_RAIter,_RAIter) 默认生成大顶堆
make_heap(_RAIter,_RAIter,_Compare) _Compare有两种参数,一种是greater(生成小顶堆),一种是less(生成大顶堆)
push_heap()是向堆中插入一个元素,并且使堆的规则依然成立
push_heap(_RAIter,_RAIter) 默认为大顶堆
push_heap(_RAIter,_RAIter,_Compare) _Compare有两种参数,一种是greater(小顶堆),一种是less(大顶堆)
调用push_heap之前必须调用make_heap创建一个堆
首先数组push_back插入元素,然后再调用push_heap,它会使最后一个元素插到合适位置
注意,push_heap中的_Compare和make_heap中的_Compare参数必须是一致的,不然会插入堆失败,最后一个元素还是在最后位置,导致插入失败
pop_heap()是在堆的基础上,弹出堆顶元素。
pop_heap(_RAIter,_RAIter) 默认为大顶堆
pop_heap(_RAIter,_RAIter,_Compare) _Compare有两种参数,一种是greater(小顶堆),一种是less(大顶堆)
比如pop_heap(nums.begin(), nums.end(),greater<int>()),它会将堆顶元素(即为数组第一个位置)和数组最后一个位置对调,然后你可以调用数组pop_back,删除这个元素
注意,pop_heap中的_Compare和make_heap中的_Compare参数必须是一致的,不然会失败
使用的时候可以不make_heap,而直接push_heap,示例如这道剑指offer上的题目数据流中的中位数。
若用make_heap(), pop_heap(), push_heap(),需要添加头文件# include <algorithm>
。
用less ()和greater () 需要添加头文件 # include <functional>
。