今天做https://www.luogu.com.cn/problem/P1168
给定一个长度为 的非负整数序列 ,对于前奇数项求中位数。
第一行一个正整数 。 第二行 个正整数 。
共 行,第 行为 的中位数。
7 1 3 5 7 9 11 6
1 3 5 6
7 3 1 5 9 8 7 6
3 3 5 6
对于 的数据,; 对于 的数据,; 对于 的数据,,。
用到的对顶堆算法
对顶堆算法(Median Maintenance Algorithm)是一种用于动态维护中位数的算法。它的核心思想是使用两个堆来分别存储数据集的较小一半和较大一半的元素,从而能够快速找到中位数。
max_heap
:大顶堆,存储较小的一半元素。min_heap
:小顶堆,存储较大的一半元素。假设输入序列为 [3, 1, 5, 9, 8, 7, 6]
,我们逐步分析:
3
:
max_heap
:[3]
min_heap
:空3
3
1
:
max_heap
:[3, 1]
min_heap
:空max_heap
的元素数量比 min_heap
多出2个,将 3
移到 min_heap
max_heap
:[1]
min_heap
:[3]
3
3
5
:
max_heap
:[5, 1]
min_heap
:[3]
max_heap
的堆顶元素 5
大于 min_heap
的堆顶元素 3
,交换max_heap
:[3, 1]
min_heap
:[5]
3
3
9
:
max_heap
:[9, 3, 1]
min_heap
:[5]
max_heap
的元素数量比 min_heap
多出2个,将 9
移到 min_heap
max_heap
:[3, 1]
min_heap
:[5, 9]
5
5
8
:
max_heap
:[8, 3, 1]
min_heap
:[5, 9]
max_heap
的堆顶元素 8
大于 min_heap
的堆顶元素 5
,交换max_heap
:[5, 3, 1]
min_heap
:[8, 9]
5
5
7
:
max_heap
:[7, 5, 3, 1]
min_heap
:[8, 9]
max_heap
的元素数量比 min_heap
多出2个,将 7
移到 min_heap
max_heap
:[5, 3, 1]
min_heap
:[7, 8, 9]
6
6
6
:
max_heap
:[6, 5, 3, 1]
min_heap
:[7, 8, 9]
max_heap
的堆顶元素 6
大于 min_heap
的堆顶元素 7
,交换max_heap
:[5, 3, 1]
min_heap
:[6, 7, 8, 9]
6
6
cpp#include <iostream>
#include <queue>
#include <vector>
using namespace std;
void find_medians(int N, vector<int>& A) {
priority_queue<int> max_heap; // 大顶堆,存储较小的一半元素
priority_queue<int, vector<int>, greater<int>> min_heap; // 小顶堆,存储较大的一半元素
for (int i = 0; i < N; ++i) {
// 将当前元素插入到大顶堆中
max_heap.push(A[i]);
// 如果大顶堆的元素数量比小顶堆的元素数量多出2个或更多
if (max_heap.size() > min_heap.size() + 1) {
// 将大顶堆的堆顶元素移到小顶堆中
min_heap.push(max_heap.top());
max_heap.pop();
}
// 如果大顶堆的堆顶元素大于小顶堆的堆顶元素
if (!min_heap.empty() && max_heap.top() > min_heap.top()) {
// 交换这两个堆的堆顶元素
int max_top = max_heap.top();
int min_top = min_heap.top();
max_heap.pop();
min_heap.pop();
max_heap.push(min_top);
min_heap.push(max_top);
}
// 如果当前处理的是奇数个元素
if ((i + 1) % 2 == 1) {
// 输出大顶堆的堆顶元素,即当前序列的中位数
cout << max_heap.top() << endl;
}
}
}
int main() {
int N;
cin >> N;
vector<int> A(N);
for (int i = 0; i < N; ++i) {
cin >> A[i];
}
find_medians(N, A);
return 0;
}
巧妙的利用了大小堆的性质
本文作者:yowayimono
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!