问题:
如何得到一个数据流中的中位数?
如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。
如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
思路:
采用堆,一个大根堆,一个小根堆。(小根堆存放偏大得数,大根堆存放偏小的数)
第一个数先读到大根堆中,
后面的数,对比大根堆堆顶,如果小于等于堆顶放入大根堆,
否则尝试放入小根堆,如果小根堆空,放入,否者对比小根堆堆顶,大于堆顶放入小根堆。否则放入大根堆。
如果两个堆个数相差>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>{
@Override
public int compare(Integer o1, Integer o2) {
// TODO Auto-generated method stub
return o2 -o1;
}
}