offer题目41:数据流中的中位数

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

分析:数据是从数据流中读出来的,它的数目随着时间的变化而增加。如果用一个容器来保存从数据流中读出来的数据,则当有新的数据从流中读出来时,这些数据就插入数据容器。可以考虑用数组来作为保存数据的容器,在已经排序好的数组中找出中位数的操作需要O(1)的时间复杂度,而向数组中来插入一个数据的时间复杂度为O(n)。

 

整个容器可以被分为两个部分,位于容器左边的部分的数据比右边的数据小。另外P1指向左边部分最大的数,P2指向右边数据最小的数。而且左右两边容器的个数相差最大为1。这样我们可以维护一个最大堆实现左边的数据容器,用一个最小堆实现右边的容器。向堆中插入一个数据的时间复杂度为O(logn),而取堆顶数据的时间复杂度为O(1)。可以较好的解决这个题目。

代码:

#include <vector>
#include <algorithm>

using namespace std;

template<typename T>
class DynamicArray{
  private:
    vector<T> min;      //最小堆  一开始为空 满足成堆的要求
    vector<T> max;      //最大堆
  public:
   void  Insert(T num){
          //大根堆与小根堆的元素个数相差不超过1。我们规定:当此时元素的总个数为偶数时,新元素插入小根堆;总个数为奇数时,插入大根堆
    if(((min.size() + max.size()) % 2) == 0){     //如果元素的总个数为偶数  新元素默认放入小根堆中
        if(max.size() > 0 && num < max[0]){           //如果新元素小于大根堆最大值,那么先将元素插入大根堆,然后取出大根堆的最大值插入小根堆中
          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 && 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();

      T median = 0;
      if((size & 1) == 1){
          median = min[0];           //如果元素的总个数为奇数,那么中位数在最小堆中,为min[0]
      }
      else {
          median = (min[0] + max[0]) / 2;  //如果元素的总个数为偶数,那么中位数为(min[0] + max[0]) / 2
      }
      return median;
   }
};


 

简单的main函数调用:

#include <iostream>


int main(){
  DynamicArray<int>  arr;
  for(int i = 0;i < 100;i++){
    arr.Insert(i);
    int meidan = arr.GetMedian();
    std::cout<<"中位数是:"<<meidan<<std::endl;
  }
  return 0;
}

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值