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

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