快速中位数-随时取得数据流的中位数

随时取得数据流的中位数


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");
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值