STL heap相关算法
STL heap相关算法
内容
C++ 标准库提供了一组底层堆操作算法(定义在 <algorithm> 头文件中),这些函数允许直接操作序列式容器(如 vector、array)来构造和操作堆。这些算法与 priority_queue 的区别在于它们 更灵活、更底层,允许开发者直接控制堆结构。以下是核心函数及其用法详解:
核心堆算法列表
| 函数名 | 作用 | 时间复杂度 | 
|---|---|---|
| std::make_heap | 将无序序列转换为堆结构 | O(n) | 
| std::push_heap | 向堆的末尾添加元素,并调整堆结构 | O(log n) | 
| std::pop_heap | 移除堆顶元素,将其放到末尾并调整堆 | O(log n) | 
| std::sort_heap | 将堆结构转换为有序序列(会破坏堆性质) | O(n log n) | 
| std::is_heap | 检查序列是否为堆 | O(n) | 
| std::is_heap_until | 返回最长满足堆性质的子序列的末尾迭代器 | O(n) | 
1. std::make_heap:构建堆
- 功能:将指定范围内的元素调整为堆结构。
- 参数:(first, last[, comp])(comp为可选的比较器)。
- 示例:#include <algorithm> #include <vector> std::vector<int> v = {3, 1, 4, 1, 5, 9}; std::make_heap(v.begin(), v.end()); // 默认构建最大堆 // v 变为 {9, 5, 4, 1, 1, 3}(堆结构,不一定是完全有序)- 若需要最小堆,传递 std::greater<>比较器:std::make_heap(v.begin(), v.end(), std::greater<int>());
 
- 若需要最小堆,传递 
2. std::push_heap:向堆中添加元素
- 功能:假设容器末尾是新插入的元素,调整堆结构使其仍满足堆性质。
- 前提:容器在调用前已满足堆性质(除了最后一个元素)。
- 示例:v.push_back(6); // 先在容器末尾添加元素 std::push_heap(v.begin(), v.end()); // 调整堆 // v 变为 {9, 5, 6, 1, 1, 3, 4}(最大堆)
3. std::pop_heap:移除堆顶元素
- 功能:将堆顶元素(最大值或最小值)移动到容器末尾,并调整剩余元素为堆。
- 示例:std::pop_heap(v.begin(), v.end()); // 将堆顶移动到末尾 // v 变为 {5, 4, 3, 1, 1, 9}(末尾元素 9 是原堆顶) int max_value = v.back(); // 获取被移除的堆顶元素 v.pop_back(); // 实际删除末尾元素
4. std::sort_heap:堆排序
- 功能:将堆结构转换为有序序列(升序或降序)。
- 注意:调用后原堆结构被破坏。
- 示例:std::sort_heap(v.begin(), v.end()); // 升序排序 // v 变为 {1, 1, 3, 4, 5, 9}
5. std::is_heap 与 std::is_heap_until
- 用途:验证堆结构或调试堆操作。std::vector<int> v = {9, 5, 4, 1, 1, 3}; bool is_heap = std::is_heap(v.begin(), v.end()); // 检查是否为堆 auto it = std::is_heap_until(v.begin(), v.end()); // 返回第一个破坏堆性质的元素位置
堆算法 vs priority_queue
| 特性 | 堆算法 | priority_queue | 
|---|---|---|
| 底层容器访问 | 可直接操作容器(如 vector) | 封装容器,只能通过 top()访问堆顶 | 
| 灵活性 | 可动态调整堆大小或部分处理堆元素 | 只能通过 push()/pop()操作 | 
| 内存控制 | 可复用现有容器内存 | 需要容器适配器(默认 vector) | 
| 适用场景 | 需要精细控制堆结构(如实现特定算法) | 简单的优先级队列需求 | 
使用场景示例
场景 1:动态维护 Top-K 元素
std::vector<int> data = {/* 流式数据 */};
std::vector<int> top_k(10); // 保留前 10 大元素
// 1. 构建最小堆(保留最大值)
std::make_heap(top_k.begin(), top_k.end(), std::greater<int>());
for (int num : data) {
    if (num > top_k.front()) { // 当前元素比堆顶大
        // 替换堆顶并调整堆
        top_k[0] = num;
        std::make_heap(top_k.begin(), top_k.end(), std::greater<int>());
    }
}
场景 2:手动实现优先队列
std::vector<int> heap;
// 插入元素
heap.push_back(new_element);
std::push_heap(heap.begin(), heap.end());
// 取出堆顶
std::pop_heap(heap.begin(), heap.end());
heap.pop_back();
性能注意事项
- make_heap的代价:频繁调用- make_heap(如场景 1)的时间复杂度为 O(k),若数据流较大,应改用- push_heap/- pop_heap(时间复杂度 O(log k))。
- 缓存友好性:堆操作在内存访问上不如数组紧凑,对性能敏感的场景可考虑使用更紧凑的数据结构(如 d-ary heap)。
总结
C++ 的堆算法提供了对堆结构的底层控制,适合需要 动态调整堆大小、复用内存或实现特定堆逻辑 的场景。而 priority_queue 作为容器适配器,更适合简单的优先级队列需求。理解这些算法可以让你在需要优化性能或实现复杂逻辑时,更灵活地操作堆结构。

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号