您的位置:首页 > 产品设计 > UI/UE

剑指offer——数据流中的中位数(好)(PriorityQueue,Comparator)

2017-07-07 14:02 302 查看
题目描述

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

思路:

使用java中util包里的PriorityQueue协助完成。

定义一个最小堆(堆顶是最小元素,该数据结构默认的比较器)

和一个最大推(堆顶是最大元素,需重新定义比较器)

最小堆中存放流中最大的一半数,最大堆中存放流中最小的一半数。中位数等于两个堆顶的数值的平均,或者其中某个堆的堆顶。

重点是在往队列中添加数据的过程中,两个队列之间的元素差始终在1以内。

private int count = 0;
private PriorityQueue<Integer> minHeap = new PriorityQueue<>(); //堆顶是最小的
private PriorityQueue<Integer> maxHeap = new PriorityQueue<>(15, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
}); // 堆顶是最大的
public void Insert(Integer num) {
count++;
if(count==1)
maxHeap.add(num);
else{
int a = maxHeap.peek();
if(num<a) {
if(maxHeap.size()>minHeap.size()){
minHeap.add(maxHeap.poll());
maxHeap.add(num);
}
else
maxHeap.add(num);
}
else{
if(minHeap.size()>maxHeap.size()){
maxHeap.add(minHeap.poll());
minHeap.add(num);
}
else
minHeap.add(num);
}
}
GetMedian();
}

public Double GetMedian() {
double result = 0;
if (count == 1)
result = maxHeap.peek();
else {
if (count % 2 != 0)
if (maxHeap.size()>minHeap.size())  //哪边是奇数,就取那个堆里的堆顶
result = maxHeap.peek();
else
result = minHeap.peek();
else
result = (double) (maxHeap.peek() + minHeap.peek()) / 2;
}
return result;
}


另一种使两堆中元素差始终保持在1以内的方法。

public void Insert(Integer num) {
if (count %2 == 0) {//当前数据总数为偶数时
//(注意不是直接进入小根堆,而是经大根堆筛选后取大根堆中最大元素进入小根堆)
//1.新加入的元素先入到大根堆,由大根堆筛选出堆中最大的元素
maxHeap.offer(num);
int filteredMaxNum = maxHeap.poll();
//2.筛选后的【大根堆中的最大元素】进入小根堆
minHeap.offer(filteredMaxNum);
} else {//当前数据总数为奇数时
//(注意不是直接进入大根堆,而是经小根堆筛选后取小根堆中最大元素进入大根堆)
//1.新加入的元素先入到小根堆,由小根堆筛选出堆中最小的元素
minHeap.offer(num);
int filteredMinNum = minHeap.poll();
//2.筛选后的【小根堆中的最小元素】进入大根堆
maxHeap.offer(filteredMinNum);
}
count++;
}

public Double GetMedian() {
if (count %2 == 0) {
return new Double((minHeap.peek() + maxHeap.peek())) / 2;
} else {
return new Double(minHeap.peek());
}
}


多用位运算

public class Solution {

PriorityQueue<Integer> big = new PriorityQueue<>();
PriorityQueue<Integer> small = new PriorityQueue<>(15, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
}); // 堆顶是最大的
int sum = 0;
public void Insert(Integer num) {
sum++;
big.offer(num);
if(sum>1){
if((sum&1)==1){
small.offer(big.poll());
big.offer(small.poll());
}
else
small.offer(big.poll());
}
}

public Double GetMedian() {
if((sum&1)==1)
return big.peek().doubleValue();
else
return (big.peek()+small.peek())/2.0;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: