题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
解题思路:
由于数据是从一个数据流中读出来的,因而数据的数目随着时间的变化而增加。如果用一个数据容器来保存从流中读出来的数据,则当有新的数据从流中读出来时,就插入数据容器。这个数据可以是数组、排序的数组、排序的链表、二叉搜索树、AVL树、最大堆和最小堆。
解题代码:
1.排序数组(来一个数据就排序一下插入) 插入时间复杂度O(n) 得到中位数复杂度O(1)
class Solution {
vector<int> v;
int n;
public:
void Insert(int num){
v.push_back(num);
n = v.size();
for(int i = n - 1; i > 0 && v[i] < v[i - 1]; --i)
swap(v[i], v[i - 1]);
}
double GetMedian(){
return (v[(n - 1) >> 1] + v[n >> 1]) / 2.0;
}
};
2. 最大堆和最小堆
最大最小堆需要满足的条件:
(1)最大最小堆任何时候元素个数之差不能大于1
(2)左边最大堆的元素最大元素不能大于右边最小堆的最小元素,以保证数据的有序性。
less( )对应最大堆排序,greater( )对应最小堆排序
做法就是用一个大顶堆和一个小顶堆,维持大顶堆的数都小于等于小顶堆的数,且两者的个数相等或差1。平均数就在两个堆顶的数之中
用priority_queue优先队列实现大顶堆和小顶堆
class Solution {
priority_queue<int, vector<int>, less<int> > p;
priority_queue<int, vector<int>, greater<int> > q;
public:
void Insert(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() + 1 == q.size()) p.push(q.top()), q.pop();
}
double GetMedian(){
return p.size() == q.size() ? (p.top() + q.top()) / 2.0 : p.top();
}
};
用push_heap 、pop_heap、及vector实现堆
class Solution {
public:
void Insert(int num)
{
if(((min.size()+max.size())& 1)==0) //数据总数为偶数,将新数据插入最小堆
{
if(max.size()>0 && num< max[0]) //如果新数据(待插入最小堆)比最大堆的一些数小
{ //则先把这个数插入最大堆,然后把最大堆中的最大数字拿去插入最小堆
max.push_back(num);
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); //将上面弹出的元素插入最小顶堆
push_heap(min.begin(),min.end(),greater<int>());// 重新对最小堆排序调整
}
else //数据总数为偶数,将新数据插入最大堆
{
if(min.size()>0 && min[0]<num) //如果新数据(待插入最大堆)比最小堆的一些数大
{
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();
double median=0;
if((size&1)==1)
median=min[0];
else
median=(min[0]+max[0])/2;
return median;
}
private:
//堆一般用vector容器实现
vector<double> min; //最小堆
vector<double> max; //最大堆
};
3.二叉搜索树
补充:
回头将优先队列学习一下,以及堆排序的结构图都搞明白
排序算法中堆排序还没有学习,待学习....
【1】堆排序 https://blog.youkuaiyun.com/her__0_0/article/details/72511047
【3】push_heap和pop_heap https://blog.youkuaiyun.com/u012273127/article/details/79629738
【4】https://www.nowcoder.com/questionTerminal/9be0172896bd43948f8a32fb954e1be1
【5】https://blog.youkuaiyun.com/lv1224/article/details/82222719