寻找一个数组的中位数C++版本(使用priority_queue)

维护一个最小堆和一个最大堆,平衡两个堆的个数,两种情况:

  • 最大堆比最小堆个数多 1
  • 最大堆和最小堆个数相同

如果个数相等,返回两个数的平均值。如果最大堆比最小堆个数多1,那么返回最大堆的堆顶元素即为中位数。
通过下面代码就可以实现:

//寻找中位数
double findMedian(vector<int>& data)
{
	if (data.size() == 0)
	{
		return -1;
	}
	priority_queue<int, vector<int>, less<int>> lessHeap;
	priority_queue<int, vector<int>, greater<int>> greaterHeap;
	for (int i = 0; i < data.size(); i++)
	{
		if (lessHeap.size() < 1 || data[i] <= lessHeap.top())
		{
			lessHeap.push(data[i]);
		}
		else {
			greaterHeap.push(data[i]);
		}
		if (lessHeap.size() == greaterHeap.size() + 2)
		{
			greaterHeap.push(lessHeap.top());
			lessHeap.pop();
		}
		if (lessHeap.size()+1 == greaterHeap.size())
		{
			lessHeap.push(greaterHeap.top());
			greaterHeap.pop();
		}
	}
	return lessHeap.size() == greaterHeap.size() ? (lessHeap.top() + greaterHeap.top()) / 2.0 : lessHeap.top();
	
}
C++中,我们可以使用优先队列(`priority_queue`)和快速选择算法(QuickSelect)来高效地计算给定数组中每个区间的中位数。这个算法的时间复杂度通常能达到O(n),对于每个查询`l, r`都是如此。 首先,我们需要对整个数组进行排序。然后,针对每个区间`[l, r]`,我们可以在O(log m)时间内到第`(r-l+1)/2`小(如果(r-l)是奇数)或第`(r-l+2)/2`小(如果(r-l)是偶数)的元素,这是由于快速选择算法的特性。这里我们使用两个堆来辅助操作: 1. 初始化两个优先队列,一个大顶堆(`greater<int>`),用于存储小于中间的元素;另一个小顶堆(`greater_equal<int>`),用于存储大于等于中间的元素。 2. 对于每个区间 `[l, r]`,从数组中取出元素并与堆进行交互,维护堆的性质: - 如果元素位于中间位置,直接返回该元素; - 如果元素比当前中间小,入大顶堆; - 如果元素比当前中间大,入小顶堆,并调整堆的大小,以保持堆的正确结构。 3. 当处理完所有元素后,如果`l`是奇数,中位数就是堆顶的大顶堆元素;如果是偶数,则中位数是堆顶元素和倒数第二个元素的平均。 以下是简单的伪代码概述: ```cpp void quick_select(vector<int>& arr, int l, int r, int k) { // ... 实现快速选择算法 } int find_median(vector<int>& nums, int start, int end, int target) { if (start == end) return nums[start]; // ... 使用快速选择到第k小的元素 priority_queue<int, vector<int>, greater<int>> max_heap; priority_queue<int, vector<int>, greater_equal<int>> min_heap; // ... 使用两个堆来到目标中位数 } int median_query(vector<int>& nums, vector<pair<int, int>>& queries) { sort(nums.begin(), nums.end()); for (auto [l, r] : queries) { cout << find_median(nums, l, r, (r-l+1)/2) << endl; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值