题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
有下面两种思路:
1. 使用一个数组保存数据流中的数据,每次insert时,使用插入排序,保证数组中的数据是从小到大排序的
2. 使用一个大顶堆和一个小顶堆保存数据,每次insert时,使大顶堆的元素都小于小顶堆的元素,并且两个堆的大小不超过2,这样,中位数就在两个堆顶之中,这种思路其实类似于平衡二叉树
代码如下:
class Solution {
public:
//方法一: 使用数组保存数据流,每次插入时,从小到大排序
vector<int> array;
void insert_array(int num){
array.push_back(num);
for(int i = array.size()-1; i > 0; i--){
if(array[i] < array[i-1]){
array[i] ^= array[i-1];
array[i-1] ^= array[i];
array[i] ^= array[i-1];
}
else{
break;
}
}
}
double get_array_median(){
int size = array.size();
if(size % 2 == 1){
return array[size / 2];
}
else{
return (array[size / 2] + array[size / 2 - 1]) / 2.0;
}
}
//方法二:使用一个大顶堆和一个小顶堆保存数据
//保证大顶堆的数,都小于小顶堆的数, 则满足排序要求
//每次你新来的数 先判断可以放到哪一个堆中
//保证两个堆的个数的差,不大于1,则平均值就在两个堆顶之中
priority_queue<int, vector<int>, less<int> > p; //大顶堆
priority_queue<int, vector<int>, greater<int> > q; //小顶堆
void insert_heap(int num){
if(p.empty() || num < p.top()){
p.push(num);
}
else{
q.push(num);
}
if(p.size() == q.size() + 2){
q.push(p.top());
p.pop();
}
if(p.size() == q.size() - 2){
p.push(q.top());
q.pop();
}
}
double get_heap_median(){
if(p.size() == q.size()){ //两个堆元素个数相同,则结果是堆顶的平均值
return (p.top() + q.top()) / 2.0;
}
else{
return p.size() > q.size() ? p.top() : q.top(); //哪个堆个数大,则结果就是哪个堆的堆顶
}
}
void Insert(int num){
//insert_array(num);
insert_heap(num);
}
double GetMedian() {
//return get_array_median();
return get_heap_median();
}
};