您的位置:首页 > 其它

中位数:得到正确的浮点数,需加一个1.0* (size&1)==0,注意有括号。

2017-03-28 21:49 316 查看


题目描述

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值

注意事项:
1.两个整数n,m,(double) n/m的结果还是整除(n/m)的结果,即使前面加了(double),因为它会先算n/m再用double对得到的整数强制转换。
所以正确的用法是(double) 1.0*n/m,这里一定要加一个1.0*,不然就得不到正确的浮点数。


class Solution {
public:
void Insert(int num)
{
myset.insert(num);
}

double GetMedian()
{
int len=myset.size();
if(len%2==0){
return (double)((getKthval(len/2)+getKthval(len/2-1))*(1.0)/2); //这个地方一定要加个*1.0,因为(double)(整/整)=整。
}else{
return (double) getKthval(len/2);
}

}

int getKthval(int k){
int cnt=0;
for(multiset<int>::iterator it=myset.begin();it!=myset.end();++it){
if(cnt==k){
return *it;
}
++cnt;
}
return 0;
}

private:
multiset<int> myset;

};

解法二:

对于数据流,对应的就是在线算法了,一道很经典的题目就是在1亿个数中找到最大的前100个数,这是一道堆应用题,找最大的前100个数,那么我们就创建一个大小为100的最小化堆,每来一个元素就与堆顶元素比较,因为堆顶元素是目前前100大数中的最小数,前来的元素如果比该元素大,那么就把原来的堆顶替换掉。 那么对于这一道题呢?如果单纯的把所有元素放到一个数组里,每次查找中位数最快也要O(n),综合下来是O(n^2)的复杂度。我们可以利用上面例子中的想法,用一个最大堆来维护当前前n/2小的元素,那么每次找中位数只到取出堆顶就可以了。但是,有一个问题,数据要动态增长,有可能之前被替换掉的元素随着元素的增加又跑回来了,所以我们不能单纯得向上题一样把元素丢掉,我们可以再用一个最小化堆来存前n/2大的元素。

分析

获取中位数有多种方法,但是各种方法的时间效率不一。下面是多种方法的时间复杂度的比较:有图可以知道使用AVL二叉平衡树的方法和使用最大堆最小堆的方法是总的时间复杂度最优的。但是AVL二叉平衡树没有现成的数据结构的实现,因此可以考虑Java集合中的PriorityQueue优先队列(也就是堆,默认为小根堆)来实现比较高校的中位数查找。



思路:考虑将数据序列从中间开始分为两个部分,左边部分使用大根堆表示,右边部分使用小根堆存储。每遍历一个数据,计数器count增加1,当count是偶数时,将数据插入小根堆;当count是奇数时,将数据插入大根堆。当所有数据遍历插入完成后(时间复杂度为O(logn),如果count最后为偶数,则中位数为大根堆堆顶元素和小根堆堆顶元素和的一半;如果count最后为奇数,则中位数为小根堆堆顶元素。

//当数据总数为偶数时,新加入的元素,应当进入小根堆      

   //(注意不是直接进入小根堆,而是经大根堆筛选后取大根堆中最大元素进入小根堆)         //1.新加入的元素先入到大根堆,由大根堆筛选出堆中最大的元素

注意:

1.&的优先级低于==的优先级。 所以 (size&1)==0,注意有括号。

2.求中位数可以使用大小堆,大小堆用STL的优先级队列来操作比较简单。

3.   priority<int,vector<int>,less<int>> maxheap; 大顶堆 9,8,7,6,5,4

    priority<int,vector<int>,greater<int>> minheap;小顶堆 1,2,3,4,5,6


class Solution {
public:
void Insert(int num)
{
int size=maxheap.size()+minheap.size();
if((size&1)==0){//草泥马,==的优先级比&高,所以这里一定要有(),调试了大半天.
minheap.push(num);
maxheap.push(minheap.top());
minheap.pop();
}else{
maxheap.push(num);
minheap.push(maxheap.top());
maxheap.pop();
}

}

double GetMedian()
{
int size=maxheap.size()+minheap.size();
if((size&1)==0){
return (minheap.top()+maxheap.top())*1.0/2;
}else{
return maxheap.top();
}
}

private:
priority_queue<int,vector<int>,less<int>> maxheap;
priority_queue<int,vector<int>,greater<int>> minheap;

};


解法三:

class Solution {
public:
void Insert(int num)
{
//大根堆始终保持“中间值”

if(maxheap.empty()||maxheap.top()>num) maxheap.push(num);
else minheap.push(num);
if(maxheap.si
c37c
ze()+1==minheap.size()) {//始终保持两个堆的大小差不大于1
maxheap.push(minheap.top());
minheap.pop();
}
if(maxheap.size()==minheap.size()+2){//这里不能=+1,因为可能上一步致使。
minheap.push(maxheap.top());
maxheap.pop();
}

}

double GetMedian()
{
return minheap.size()==maxheap.size()?((minheap.top()+maxheap.top())*1.0/2):maxheap.top();
}

private:
priority_queue<int,vector<int>,less<int>> maxheap;
priority_queue<int,vector<int>,greater<int>> minheap;

};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐