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

34 篇文章 0 订阅
8 篇文章 0 订阅

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




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
计算数据流中位数可以通过Flink的ProcessFunction来实现。 具体实现步骤如下: 1. 将数据流按照大小排序 2. 计算数据流的长度,如果是奇数,则中位数为第 (length+1)/2 个元素;如果是偶数,则中位数为第length/2个元素和第(length/2+1)个元素的平均值。 3. 在ProcessFunction的实现中,可以使用状态变量来保存数据流的有序列表,并计算中位数。 以下是一个简单的示例代码: ```java public class MedianFunction extends ProcessFunction<Integer, Double> { private ListState<Integer> values; @Override public void open(Configuration parameters) throws Exception { super.open(parameters); values = getRuntimeContext().getListState(new ListStateDescriptor<Integer>("values", Integer.class)); } @Override public void processElement(Integer value, Context ctx, Collector<Double> out) throws Exception { values.add(value); List<Integer> sortedValues = new ArrayList<>(); for (Integer v : values.get()) { sortedValues.add(v); } Collections.sort(sortedValues); int length = sortedValues.size(); if (length % 2 == 0) { double median = (sortedValues.get(length/2) + sortedValues.get(length/2 - 1)) / 2.0; out.collect(median); } else { double median = sortedValues.get(length/2); out.collect(median); } } } ``` 在上述代码中,我们使用了ListState来保存数据流中的元素,并在每次处理新元素时重新排序并计算中位数。注意,这只是一个简单的示例,实际应用中需要考虑更多的问题,比如数据倾斜、数据丢失等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值