C++ 动态中位数(Dynamic Median)

题目

输入一组整数a1,a2,,ana1, a2, …, an ,每输入一个整数,输出到此时为止的中位数。时间复杂度不超过O(nlogn)O(nlogn)

此处中位数定义:如果数串的大小是偶数 2j2j,中位数是从小到大排列的第 jj个数;如果数串的大小是奇数 2j+12j+1,中位数是从小到大排列的第 j+1j+1 个数。

Sample

Input

-18 -2 14 -20 -6 7 2 14 11 6

Output

-18 -18 -2 -18 -6 -6 -2 -2 2 2

思路

利用快排的变式我们有O(n)O(n)的寻找给定数组中位数的方法,但从本题时间复杂度不难分析出要求的每次求中位数的代价为O(logn)O(logn),于是联想到树/堆。

堆具有偏序特性,可以保证所有父节点的值大于(或小于)子节点的值。找最值很方便,取根节点就行,但这里需要的是中位数。有没有什么办法让根节点与中位数产生关系?很简单,让根节点是数组中较小的一半元素的最大值,就行了,于是我们便可以用两个堆构成的漏斗型结构来处理。

漏斗的连接处是两个堆的根节点,较小的一半元素存在下部的大顶堆中,较大的一半元素存在上部的小顶堆中。在元素的输入过程中维护这两个堆。于是取中位数便很简单了,找根节点就行了。

当然,这里还有一些细节,比如如何保证两个堆确实是接近一半一半呢?考虑到中位数的定义我们知道

  • heapMax.size==heapMin.size(+1)heapMax.size==heapMin.size(+1)时,大顶堆的根节点是中位数
  • heapMax.size==heapMin.size1heapMax.size==heapMin.size-1时,小顶堆的根节点是中位数

当两个堆的元素不满足上述关系时,中位数便不是根节点。我们可以在发现sizesize相差超过1时将大顶堆的根节点上浮或者把小顶堆的根节点元素下沉,保持这个关系,最后输出就会很方便。

代码

int main()
{
	Heap hMax(true);  // 大顶堆
	Heap hMin(false); //小顶堆
	int k;
	while (scanf("%d", &k))
	{	// ***每次添加/删除元素后都应进行堆的维护***
		
		// 初始放入
		if (hMax.get_len() == 0)
		{
			hMax.add_elem(k);
			printf("%d ", hMax.get_top());
			continue;
		}
		// 判断当前元素应该放在上面还是下面
		if (k < hMax.get_top())
		{
			hMax.add_elem(k);
		}
		else
		{
			hMin.add_elem(k);
		}
		// 保证两个heap元素数相差<=1
		if (hMax.get_len() > hMin.get_len() + 1)
		{
			int maxTop = hMax.pop();
			hMin.add_elem(maxTop);
		}
		else if (hMin.get_len() > hMax.get_len() + 1)
		{
			int minTop = hMin.pop();
			hMax.add_elem(minTop);
		}
		// 输出中位数
		if (hMax.get_len() >= hMin.get_len())
		{
			printf("%d ", hMax.get_top());
		}
		else
		{
			printf("%d ", hMin.get_top());
		}
		if (getchar() == '\n')
			break;
	}
	system("PAUSE");
	return 0;
}
发布了2 篇原创文章 · 获赞 1 · 访问量 31
展开阅读全文
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 游动-白 设计师: 上身试试

分享到微信朋友圈

×

扫一扫,手机浏览