(算法总结)堆排序的应用:寻找中位数

设计一个数据结构,可动态地维护一组数据,且支持如下操作:

(1)添加元素:void addNum(int num)

(2)返回这组数据中的中位数 double findMedian()

【思考】如何获取一组元素的中位数

(1)首先,我们马上想到的方法,最直观的方法就是:添加元素的同时进行排序操作(直插sort)addNum的复杂度是O(n),findMedian的复杂度则是O(1);

(2)我们也可以考虑在查询中位数的时候进行排序,这样addNum的复杂度是O(1),而findMedian的复杂度则是O(nlogn)。然而,如果addNum和findMedian的操作都是随机操作,共进行n次,则整体的时间复杂度最佳为O(n2)

这样的复杂度很明显不能满足要求,因此,我们需要试图寻找最佳的解决策略,这里我们巧妙地利用了堆的性质:

这里,我们动态地维护了一个大顶堆 max_heap 和一个小顶堆 min_heap,这两个堆各自存放“一半”的数据(这里的“一半”是指两个堆的size()相差小于等于1),且维持 max_heap 的堆顶 <= min_heap 的堆顶。如何实现呢?我们这样设计:

在插入新元素x时,如果max_heap为空,直接将x压入max_heap;

否则,先比较 max_heap.size() 与 min_heap.size():

    若max_heap与min_heap元素个数相同:

        若 x < max_heap 的堆顶,将x压入 max_heap;

        否则,将x压入 min_heap;

    若 max_heap 比 min_heap 的size小(需要通过调整两个堆,以保证平衡):

        若 x < max_heap 的堆顶,直接将x压入 max_heap;

        否则,将 min_heap 的堆顶弹出并压入 max_heap,再将x压入min_heap

   若 max_heap 比 min_heap 的size大(同样需要通过调整两个堆):

        若 x > max_heap 的堆顶,直接将x压入 min_heap;

        否则,将 max_heap 的堆顶弹出并压入 min_heap,再将x压入max_heap

至此addNum()的流程已经完成,接下来需要考虑如何求中位数了。

    若max_heap与min_heap元素个数相同:

        median = max_heap 的堆顶与 min_heap 的堆顶的算数平均值

    若 max_heap 比 min_heap 的size小:

        median = min_heap 的堆顶

    否则:

        median = max_heap 的堆顶

 

代码如下:

class MedianFinder {
public:
	void addNum(int num);
	double find_median();
private:
	std::priority queue<int, std::vector<int>, std::less<int>> max_heap;
	std::priority queue<int, std::vector<int>, std::greater<int>> min_heap;
};
void MedianFinder::addNum(int num) {
	if (max_heap.empty()) {
		max_heap.push(num);
		return;
	}
	if (max_heap.size() == min_heap.size()) {
		if (num < max_heap.top()) {
			max_heap.push(num);
		} else {
			min_heap.push(num);
		}
	} else if (max_heap.size() < min_heap.size()) {
		if (num < max_heap.top()) {
			max_heap.push(num);
		} else {
			max_heap.push(min_heap.top());
			min_heap.pop();
			min_heap.push(num);
		}
	} else {
		if (num < max_heap.top()) {
			min_heap.push(max_heap.top());
			max_heap.pop();
			max_heap.push(num);
		} else {
			min_heap.push(num);
		}
	}
}
int MedianFinder::find_median() {
	if (max_heap.size() == min_heap.size()) {
		return (max_heap.top() + min_heap.top()) / 2.0;
	} else if (max_heap.size() < min_heap.size()) {
		return min_heap.top();
	}
	return max_heap.top();
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值