随时取得数据流的中位数
package 算法初级;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import tool.MyArraysTool;
/**
*
* @title 快速取中位数
* @description 有一个源源不断地吐出整数的数据流,假设你有足够的空间来保存吐出的数。
* 请设计一个名叫MedianHolder的结构,MedianHolder可以随时取得之前吐出所有数的中位数。
* 1、如果MedianHolder已经保存了吐出的N个数,那么任意时刻将一个新数加入到MedianHolder的过程,其时间复杂度是O(logN)。
* 2.取得已经吐出的N个数整体的中位数的过程,时间复杂度为O(1)。
* @thinking 大根堆+小根堆,大根堆始终存当前所有数据的较小的一半,小根堆始终存当前所有数据较大的一半 ;一直往小根堆放数据,然后调整
* @author xiaox
* @data 2018年5月16日
*/
public class MadianQuick {
public static class MedianHolder {
PriorityQueue<Integer> minHeap;
PriorityQueue<Integer> maxHeap;
public MedianHolder() {
this.minHeap = new PriorityQueue<Integer>();
this.maxHeap = new PriorityQueue<Integer>(new MaxComparator());
}
// 输入数据
public void input(int i) {
// 向大根堆放数据,当大根堆为空的时候直接往里放数据,当当前数据小于等于大根堆中元素时候,也放入大根堆。否则放入小根堆。然后调整两个堆中元素数量
if (maxHeap.isEmpty() || maxHeap.peek() >= i) {
maxHeap.add(i);
} else {
minHeap.add(i);
}
modifyTwoHeaps();
}
// 两个堆内数据变化后就需要调整堆
private void modifyTwoHeaps() {
while (Math.abs(minHeap.size() - maxHeap.size()) > 1) {
if (minHeap.size() > maxHeap.size()) {
maxHeap.add(minHeap.poll());
} else {
minHeap.add(maxHeap.poll());
}
}
}
// 获得已经输出流的中位数
public Integer getMadian() {
if (minHeap.size() + maxHeap.size() == 0) {
return null;
}
if (minHeap.size() > maxHeap.size()) {
return minHeap.peek();
} else if (maxHeap.size() > minHeap.size()) {
return maxHeap.peek();
} else {
return (maxHeap.peek() + minHeap.peek()) / 2;
}
}
}
public static class MaxComparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
}
// 比较器
public static Integer getMadianOfArray(int[] arr) {
Arrays.sort(arr);
int length = arr.length;
int mid = length / 2;
if (length == 0)
return arr[0];
if (length % 2 == 0) {
return (arr[mid] + arr[mid - 1]) / 2;
} else {
return arr[mid];
}
}
public static void main(String[] args) {
boolean err = false;
int testTimes = 200000;
for (int i = 0; i != testTimes; i++) {
int len = 30;
int maxValue = 1000;
int[] arr = MyArraysTool.generateArray(len, maxValue);
MedianHolder medianHold = new MedianHolder();
for (int j = 0; j != arr.length; j++) {
medianHold.input(arr[j]);
}
if (arr.length != 0)
if ((int) medianHold.getMadian() != (int) getMadianOfArray(arr)) {
err = true;
MyArraysTool.printArray(arr);
break;
}
}
System.out.println(err ? "fuck" : "yes");
}
}