火龙信奥
  • 首页
  • 课程
  • 题库
  • 打卡
    • 代码对战
    • 快速对战
  • 题单
  • 团队
  • 荣誉墙
  • 商城
  • 登录 / 注册

STL容器栈、队列、双端队列、优先队列以及对顶堆

作者: 作者的头像   huolong , 时间:2025-09-22 10:07:59 , 所有人可见, 阅读  18

其他数据结构

stack (栈): push(), pop(), top(), ...
queue (队列): push(), pop(), front(), back(), ...
deque (双端队列): push_back(), push_front(), 支持迭代器, ...
priority_queue (优先队列): 带有优先级的队列(默认:降序排列,即最大值优先,不是升序)
priority_queue<int> pq;
int zahlen[] = {1, 7, 8, 3, 12, 6, 5, 2};
for (int i: zahlen) 
    pq.push(i);

while (!pq.empty()){
    cout << pq.top() << " "; // 输出堆顶(当前最大值)
    pq.pop();                // 移除堆顶元素
}
cout << endl;

输出:

12 8 7 6 5 3 2 1

一个非常经典的应用:使用对顶堆(一个大根堆和一个小根堆)来动态地求解第K大(或第K小)的数。

问题场景

假设我们有一个数据流,需要在任意时刻都能快速查询当前所有已读入数字中的第K大的数。

核心思想:对顶堆

使用两个优先队列 (priority_queue): 大根堆 (max_heap): 用于存储所有数字中较小的那部分。堆顶是这部分中的最大值。 小根堆 (min_heap): 用于存储所有数字中较大的那部分。堆顶是这部分中的最小值。

关键维护条件:让小根堆的大小恰好等于 K。

这意味着小根堆里存放的是当前所有数字中最大的K个数。 因此,小根堆的堆顶就是这K个数中最小的,也就是第K大的数。

算法步骤 (求第K大)

初始化: 创建一个大根堆 max_heap (在C++中通过 priority_queue<int> 实现)。 创建一个小根堆 min_heap (在C++中通过 priority_queue<int, vector<int>, greater<int> >实现)。 设定目标 K。 处理每个新数字 num:

情况1: 如果 min_heap 的大小小于 K。

直接将 num 加入 min_heap。 (因为还没满K个,先放进去)

情况2: 如果 min_heap 的大小等于 K。

比较 num 和 min_heap 的堆顶 min_heap.top()。

如果 num > min_heap.top():

说明 num 比当前第K大的数还大,它有资格进入“最大的K个数”这个集合。 将 min_heap 的堆顶(即当前的第K大)弹出并加入 max_heap。 将新的 num 加入 min_heap。 (这样 min_heap 仍然是K个最大的数,且第K大被更新)

如果 num <= min_heap.top():

说明 num 不够大,进不了“最大的K个数”集合。 直接将 num 加入 max_heap。

查询第K大:

只要 min_heap 的大小等于 K,min_heap.top() 就是当前的第K大数。 如果总数字少于 K,则第K大不存在。

C++ 代码示例

#include <iostream>
#include <queue>
#include <vector>
using namespace std;

// 全局变量
priority_queue<int> max_heap; // 大根堆,存储较小的部分
priority_queue<int, vector<int>, greater<int>> min_heap; // 小根堆,存储最大的K个数
int K; // 目标:求第K大

// 添加一个数字到数据流
void addNumber(int num) {
    if (min_heap.size() < K) {
        min_heap.push(num);
    } else {
        if (num > min_heap.top()) {
            max_heap.push(min_heap.top());
            min_heap.pop();
            min_heap.push(num);
        } else {
            max_heap.push(num);
        }
    }
}

// 获取当前第K大的数
int getKthLargest() {
    return min_heap.size() == K ? min_heap.top() : -1; // 简化返回,ACM中通常保证数据足够
}

int main() {
    // 输入K
    cin >> K;

    // 模拟数据流,这里用vector代替,ACM中可能是while循环读入
    vector<int> stream = {4, 5, 8, 2, 3, 9, 7};

    cout << "Processing stream: ";
    for (int num : stream) {
        cout << num << " ";
        addNumber(num);
        int kth = getKthLargest();
        if (kth != -1) {
            cout << "(Kth largest now: " << kth << ") ";
        }
    }
    cout << endl;

    cout << "The " << K << "rd largest number is: " << getKthLargest() << endl;

    return 0;
}

输出示例

Processing stream: 4 5 8 (Kth largest now: 4) 2 3 (Kth largest now: 4) 9 (Kth largest now: 5) 7 (Kth largest now: 7) 
The 3rd largest number is: 7

解释 加入 4, 5, 8 后,min_heap 有 {4, 5, 8} (内部是小根堆,堆顶4),第3大是 4。 加入 2, 3 后,它们小于4,进入 max_heap。min_heap 不变,第3大仍是 4。 加入 9,9 > 4,所以4被弹出到 max_heap,9进入 min_heap。现在 min_heap 有 {5, 8, 9},堆顶是5,第3大变为 5。 加入 7,7 > 5,所以5被弹出到 max_heap,7进入 min_heap。现在 min_heap 有 {7, 8, 9},堆顶是7,第3大变为 7。 这种方法的时间复杂度是 O(log K) 插入和 O(1) 查询,非常高效。

—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com

©2026加盟我们 | 关于我们 | ACM课程 | 常见问题 | 成果墙 | 评测记录 | 浙ICP备2021013995号
在线画图 | OI WIki | 打字练习
火龙信奥
请输入登录信息


请完成安全验证
验证码底图 滑块
向右拖动滑块完成验证
请输入用户名 / 绑定的手机号码



请输入注册信息(手机号验证码注册)





验证码5分钟有效,60秒内不可重复获取,每日最多3次

微信登录

微信登录二维码

正在生成二维码...

账号已过期,请续期。
去续期

绑定手机号

📱

为了更好地保护您的账号安全,享受完整的平台服务

请您尽快绑定手机号码