题目描述

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

题解

首先想到的就是可以用大顶堆小顶堆来解决这个问题;但是队列好久没有使用了,那就得复习一下队列的一些常用方法:
增加:
①add(): 增加一个元索 (如果队列已满,则抛出一个IIIegaISlabEepeplian异常 )
②put(): 添加一个元素 (如果队列满,则阻塞)
③offer(): 添加一个元素并返回true (如果队列已满,则返回false)
移除:
①remove(): 移除并返回队列头部的元素 (如果队列为空,则抛出一个NoSuchElementException异常)
②take(): 移除并返回队列头部的元素 (如果队列为空,则阻塞)
③poll(): 移除并返问队列头部的元素 (如果队列为空,则返回null)
获取:
①element(): 返回队列头部的元素 (如果队列为空,则抛出一个NoSuchElementException异常)
②peek(): 返回队列头部的元素 (如果队列为空,则返回null)

解题思路

大顶堆存放小的数字,从大到小排序、小顶堆存放大的数字,从小到大排序:
用一个count记录当前的次数,从0开始,偶数个的时候先进入大顶堆,然后弹出第一个到小顶堆;奇数个的时候,先进入小顶堆,然后弹出第一个到大顶堆;
读数时:当两个堆的大小一致时,取两者的平均数;当大顶堆大于小顶堆的大小时,返回大顶堆的头部;当小顶堆大小大于大顶堆时,返回小顶堆的头部;

代码演示

    // 小顶堆
    private PriorityQueue<Integer> minHeap = new PriorityQueue<>();
    // 大顶堆
    private PriorityQueue<Integer> maxHeap = new PriorityQueue<>((o1,o2) ->o2 -o1);
    // 记录当前次数 从0开始
    private int count = 0;
    public void Insert(Integer num) {
        if (count % 2 == 0){
            maxHeap.offer(num);
            int max = maxHeap.poll();
            minHeap.offer(max);
        }else {
            minHeap.offer(num);
            int min = minHeap.poll();
            maxHeap.offer(min);
        }
        count ++ ;
    }

    public Double GetMedian() {
        if (minHeap.size() == maxHeap.size()){
            return (double) (minHeap.peek() + maxHeap.peek()) / 2.0;
        }else if (minHeap.size() < maxHeap.size()){
            return maxHeap.peek() / 1.0;
        }else{
            return minHeap.peek() / 1.0;
        }
    }