先来讲一下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;
};