码迷,mamicode.com
首页 > 其他好文 > 详细

64 - 数据流中的中位数 || STL 堆

时间:2015-08-02 18:17:31      阅读:160      评论:0      收藏:0      [点我收藏+]

标签:数据流      

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


思路解析

数据是从数据流读出,因此数组的个数是再逐渐的增加。如何选用一个容器,能够存储数据,并能够给出中位数。

  • 无序数组:插入O(1) partation操作找出中位数 O(n)
  • 有序数组:插入O(n) 找出中位数O(1)
  • 有序链表:插入O(n) 找出中位数O(1)
  • 搜索二叉树:插入O(logn)~O(n),找出中位数O(logn)~O(n)
  • AVL:插入O(logn),在节点中添加计数信息,找出中位数O(1)

如果将容器中的数据按照顺序排列,那么最中间的两个数或者一个数,可以将数据平均分成2部分。
那么以偶数个数据节点为例:最中间的两个数中的左侧数字,是前一半数据的最大值;中间数右侧数字,是后一半数据的最小值。因此只要保证,数据能够平均分成2部分,前一部分都小于后一部分,那么中位数是前一部分的最大值和后一部分的最小值的平均值。

为了实现O(1)得到最大最小值,采用最大堆保存前一半数据,最小堆保存后一半数据
为了实现平均:当容器中数据个数是偶数:插入到最小堆;总数是奇数,插入到最大堆。

当总数是偶数时,应该插入最小堆,但如果此时的数据小于最大堆的最大值,即按值大小来说,它应该属于前一部分(最大堆);因此我们将该值插入到最大堆,然后取出最大堆中的最大值,插入到最小堆。
同理,奇数时,数据大于最小堆的最小值,也应该先如最小堆,将最小堆中的最小值,移动到最大堆。

关于 C++ STL 堆的知识:

heap 的头文件 #include<algorithm>
注意:_First, _Last 是容器的迭代器,如vector。
参考:c++中STL之heap, priority_queue使用

1. make_heap

make_heap(_First, _Last)
make_heap(_First, _Last, _Comp) // 对2个迭代器之间的元素建堆

默认是建立最大堆的。对int类型,可以在第三个参数传入greater<int>()得到最小堆

2. push_heap

push_heap(_First, _Last) // 首先在容器中添加一个元素,然后push_heap,处理最后添加的一个元素

新添加一个元素在末尾,然后重新调整堆序。也就是把元素添加在底层vector的end()处。每次只能处理 1 个。

3. pop_heap

pop_heap(_First, _Last) // 先pop_heap,然后在容器中pop

这个算法跟push_heap类似,参数一样。不同的是我们把堆顶元素取出来,放到了数组或者是vector的末尾,用原来末尾元素去替代,然后end迭代器减1

4. sort_heap

.sort_heap(_First, _Last) // 堆排序

template<class T>
class DynamicArray {
private:
    vector<T> max; // 数组的前一半一半最大堆,最大堆中的数全部小于最小堆
    vector<T> min; // 数组的后一半构成最小堆,
public:
    void Insert(T num) {
        // 已有元素总数是偶数,插入最小堆
        if (((min.size() + max.size()) & 0x01) == 0) {
            if (max.size() > 0 && num < max[0]) {
                // num 小于最小堆的最小值,按值看应该插入最大堆,因此,先插入max,将max中的最大值,移动到min
                max.push_back(num);
                push_heap(max.begin(), max.end(), less<T>());
                num = max[0]; // 取出最大堆的最大值,插入到最小堆
                pop_heap(max.begin(), max.end(), less<T>());
                max.pop_back();
            }
            min.push_back(num);
            push_heap(min.begin(), min.end(), greater<T>());
        } else {
            // 已有元素总数是奇数,插入最大堆
            if (min.size() > 0 && num > min[0]) {
                // num 大于最大堆的最大值,按值看应该插入最小堆
                min.push_back(num);
                push_heap(min.begin(), min.end(), greater<T>());
                num = min[0];
                pop_heap(min.begin(), min.end(), greater<T>());
                min.pop_back();
            }
            max.push_back(num);
            push_heap(max.begin(), max.end(), less<T>());
        }
    };
    T GetMedian() {
        int size = min.size() + max.size();
        if (size == 0)
            throw exception("No numbers are avliable");
        if ((size & 0x01) == 1)
            return min[0];
        else
            return (min[0]+max[0])/2;
    }
};

测试案例:《剑指offer》 GitHub

版权声明:本文为博主原创文章,未经博主允许不得转载。

64 - 数据流中的中位数 || STL 堆

标签:数据流      

原文地址:http://blog.csdn.net/quzhongxin/article/details/47208927

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!