数组--11-中位数

题目:

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

思路:

用大顶堆实现左边的的数据容器,小顶堆实现右边的数据容器。

有一点需要注意,我们要保证数据被平均分配到两个堆中,因此两堆大小之差不能超过1。实现方法是数据流中奇数位的数插入小顶堆中,偶数位的数插入大顶堆中。

同时还要保证大顶堆中的所有数都要小于小顶堆中的数。考虑一种特殊情况,例如,插入偶数位的数,按照分配规则应该插入大顶堆中,但是这个数大于小顶堆的最小值怎么办?如果直接插入大顶堆,就不符合大顶堆所有值都小于小顶堆的值这一条件。可以这样解决:想把该数插入小顶堆,然后进行堆排序,接着讲小顶堆的最小值拿出来插入到大顶堆中,这样就满足所有条件了。同理插入奇数位的数时也要考虑这种特殊情况。

    往堆中插入一个数据时间复杂度为O(logn),而得到最大值(或最小值)只需O(1)时间。

class Solution {
public:
    void Insert(int num)
    {
        // 如果已有数据为偶数,则放入最小堆
        if(((max.size() + min.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 && num > min[0]){
                // 将数据插入最小堆
                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();
        if(size == 0){
            return 0;
        }
        // 如果数据为偶数
        if((size & 1) == 0){
            return (min[0] + max[0]) / 2.0;
        }
        // 奇数
        else{
            return min[0];
        }
    }
private:
    // 使用vector建立最大堆和最小堆,min是最小堆数组,max是最大堆数组
    vector<int> min;
    vector<int> max;
};

猜你喜欢

转载自blog.csdn.net/ax_hacker/article/details/81098847