美文网首页
面试题41:数据流的中位数

面试题41:数据流的中位数

作者: 繁星追逐 | 来源:发表于2019-11-12 14:22 被阅读0次

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

思路一:
使用两个优先队列,一个作为最大堆记录左边的元素,一个作为最小堆记录右边的元素,必须保证两边元素相等或者相差一,所以我们使用一个全局变量记录个数,把偶数位增加到左边数字最大堆,奇数位增加到右边数字最小堆,过程比较调整。如果插入到最小堆的元素比最大堆的顶元素小,则交换插入,否则直接插入小堆,
如果插入到最大堆的元素比最小堆的对顶元素大,则交换插入,否则插入大堆。最后总个数为奇数,则去最大堆对顶,为偶数则取堆顶元素平均。
代码如下:

 /**思路:
     为了保证插入新数据和取中位数的时间效率都高效,这里使用大顶堆+小顶堆的容器,并且满足:
     1、两个堆中的数据数目差不能超过1,这样可以使中位数只会出现在两个堆的交接处;
     2、大顶堆的所有数据都小于小顶堆,这样就满足了排序要求。
     * 将序列分为两个堆,一个最大堆,一个最小堆,总个数为奇数就是多的那个堆的根节点
     * 总个数是偶数就是两个堆根节点的平均数
     * @param num
     */
    private PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
    private PriorityQueue<Integer> minHeap = new PriorityQueue<>();
    private int count = 0;
    public void Insert(Integer num) {
       if (count == 0){
           maxHeap.offer(num);
       }
       //如果是奇数,插入最小堆
       else if ((count & 1) == 1){
           //必须判断插入最小堆的值必须大于最大堆的最大值
           if (num < maxHeap.peek()){
               minHeap.offer(maxHeap.poll());
               maxHeap.offer(num);
           }else {
               minHeap.offer(num);
           }
       }
       //如果是偶数就插入最大堆
        else {
            //保证插入最大堆的比最小堆的最小元素要小
           if (num > minHeap.peek()){
               maxHeap.offer(minHeap.poll());
               minHeap.offer(num);
           }else {
               maxHeap.offer(num);
           }
       }
       //记录下全局的数量
       count++;
    }

    public Double GetMedian() {
       if ((count & 1) == 1) return Double.valueOf(maxHeap.peek());
       //除以2放在外面,保证精度
       else return Double.valueOf((maxHeap.peek()+minHeap.peek()))/2;
    }

相关文章

网友评论

      本文标题:面试题41:数据流的中位数

      本文链接:https://www.haomeiwen.com/subject/pvzluctx.html