问题:
如何得到一个数据流中的中位数?
如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。
如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
思路:
采用堆,一个大根堆,一个小根堆。(小根堆存放偏大得数,大根堆存放偏小的数)
第一个数先读到大根堆中,
后面的数,对比大根堆堆顶,如果小于等于堆顶放入大根堆,
否则尝试放入小根堆,如果小根堆空,放入,否者对比小根堆堆顶,大于堆顶放入小根堆。否则放入大根堆。
如果两个堆个数相差>1;取出数量多的堆顶,放到数目少的里面。
public static class MedianHolder{PriorityQueue<Integer> minHeap;PriorityQueue<Integer> maxHeap;public MedianHolder(){this.minHeap = new PriorityQueue<>();this.maxHeap = new PriorityQueue<>(new MaxHeapComparator());}public void modify() {int count = maxHeap.size() - minHeap.size();if (Math.abs(count) >1) {if(count >0) {minHeap.add(maxHeap.poll());}else {maxHeap.add(minHeap.poll());}}}//naive!!!!!要考虑全面!!为空呢?public void add (int num) {if(maxHeap.isEmpty()) {maxHeap.add(num);return ;}if(num <= maxHeap.peek()) {//注意这里是小于大根堆堆顶maxHeap.add(num);}else {//否者尝试放入小根堆,尝试!!!尝试!!!if(minHeap.isEmpty()) {minHeap.add(num);return ;}if(num >= minHeap.peek()) {minHeap.add(num);}else {maxHeap.add(num);}}modify();}public Integer getMedian() {int maxHeapSize = maxHeap.size();int minHeapSize = minHeap.size();if (maxHeap.isEmpty() && minHeap.isEmpty()) {return null;}Integer maxHeapHead = maxHeap.peek();Integer minHeadHead = minHeap.peek();if(((maxHeapSize + minHeapSize) & 1) == 0){return (maxHeapHead + minHeadHead)/2;}return minHeapSize > maxHeapSize ? minHeadHead :maxHeapHead;}}public static class MaxHeapComparator implements Comparator<Integer>{@Overridepublic int compare(Integer o1, Integer o2) {// TODO Auto-generated method stubreturn o2 -o1;}}
