您的位置:首页 > 其它

数据流中所有数排序之后的中位数

2015-12-10 21:31 423 查看
先来讲一下STL中make_heap   push_heap   pop_heap这三个模板函数的用法。

template <class RandomAccessIterator>
void make_heap (RandomAccessIterator first, RandomAccessIterator last);

template <class RandomAccessIterator, class Compare>
void make_heap (RandomAccessIterator first, RandomAccessIterator last,
Compare comp );


make_heap模板函数有两个重载定义,对于第一个,是使用<运算符来进行比较的,默认建立的是大顶堆,第二个则是允许自定义二元谓词,接收两个参数,返回bool值。简单地说,comp既可以是函数指针,也可以是函数对象。

建堆的时间复杂度为O(2n),也就是O(n)。算法导论上有证明。

make_heap实现的功能是,把[first,last) 区间内的所有元素在O(n)时间内建成堆。

下面来讲push_heap

template <class RandomAccessIterator>
void push_heap (RandomAccessIterator first, RandomAccessIterator last);

template <class RandomAccessIterator, class Compare>
void push_heap (RandomAccessIterator first, RandomAccessIterator last,
Compare comp);


单看函数声明的话,确实看不出和make_heap的区别。调用push_heap时,调用者要保证 [first,last-1) 已经是堆了,然后push_heap负责把 [first,last)变换成堆,也就是push_heap从最后一个非叶子结点开始,依次向上调整堆。

还剩最后一个,pop_heap

template <class RandomAccessIterator>
void pop_heap (RandomAccessIterator first, RandomAccessIterator last);

template <class RandomAccessIterator, class Compare>
void pop_heap (RandomAccessIterator first, RandomAccessIterator last,
Compare comp);
调用pop_heap时,调用者必须保证 [first,last)已经是堆了,然后pop_heap负责把first的值与last-1的值交换,并对最高点进行调整,最终保证 [first,last-1) 是堆。

=====================================

数据流中所有数排序之后的中位数

分别建立两个堆,来存储从输入流中依次读取的各个数值。左边的堆用来存储从小到大排序后,所有数的前半部分。右边的堆用来存储后半部分。即左边堆中的数永远小于右边堆中的数。

左边的用大顶堆,右边的大数用小顶堆。

从1开始计数。

1.当数字为奇数时,插入左边大顶堆;

2.当数字为偶数时,插入右边小顶堆。

3.对于要插入左边的新数字,若其大于右边堆顶的数字,则将右边堆顶的数字弹出并插入左边的堆,同时,将新数字插入右边的堆。

4.对于要插入右边的数字,若其小于左边堆顶的最大值,则将左边堆顶的数字弹出并插入右边的堆,同时,将新数字插入左边的堆。

class Solution {
public:
void Insert(int num)
{
if ((leftMin.size() + rightMax.size() + 1) % 2)
{
//本来该插入到左边的大顶堆中
if (leftMin.empty() || rightMax.empty() || rightMax[0] >= num)
{
leftMin.push_back(num);
std::push_heap<std::vector<int>::iterator>(leftMin.begin(), leftMin.end());
}
else
{
int temp = rightMax[0];
std::pop_heap<std::vector<int>::iterator>(rightMax.begin(), rightMax.end(), Greator);
rightMax.back() = num;
std::push_heap<std::vector<int>::iterator>(rightMax.begin(), rightMax.end(), Greator);
leftMin.push_back(temp);
std::push_heap<std::vector<int>::iterator>(leftMin.begin(), leftMin.end());
}
return;
}
else //本来该插入到右边小顶堆的
{
if (num >= leftMin[0])
{
rightMax.push_back(num);
std::push_heap<std::vector<int>::iterator>(rightMax.begin(), rightMax.end(), Greator);
}
else
{
int temp = leftMin[0];
std::pop_heap<std::vector<int>::iterator>(leftMin.begin(), leftMin.end());
leftMin.back() = num;
std::push_heap<std::vector<int>::iterator>(leftMin.begin(), leftMin.end());
rightMax.push_back(temp);
std::push_heap<std::vector<int>::iterator>(rightMax.begin(), rightMax.end(), Greator);
}
return;
}

}

static bool Greator(int a, int b)
{
if (a > b)
return true;
else
return false;
}
double GetMedian()
{
int counter = leftMin.size() + rightMax.size();
double ret = 0;
if (1 == counter)
ret = leftMin[0];
else if (counter % 2)
ret = leftMin[0];
else
ret = (leftMin[0] + rightMax[0]) / 2.0;

return ret;
}
private:
std::vector<int> leftMin, rightMax;
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: