16、堆基础知识点和priority_queue的模拟实现

一、priority_queue的使用方法

priority_queue的使用方法看这篇文章

二、堆

1、介绍

堆(Heap)是一种特殊的完全二叉树数据结构,满足以下性质:

  • 堆序性质(Heap Property):
    • 大顶堆(Max-Heap):每个节点的值 ≥ 其子节点的值。
    • 小顶堆(Min-Heap):每个节点的值 ≤ 其子节点的值。
    • 完全二叉树:除最后一层外 ,其他层节点必须填满 ,且最后一层节点靠左排列

2、存储方式

堆的存储方式

堆通常用数组实现,利用完全二叉树的性质:

  • 对于节点 i(从 0 开始):
    • 父节点:(i - 1) / 2
    • 左子节点:2i + 1
    • 右子节点:2i + 2

3、堆的操作过程

  • 堆的常用操作

      1. 插入元素(Push)
    • 步骤:
      • 将新元素添加到数组末尾。
      • 上浮(Percolate Up):从该节点向上比较并交换,直到满足堆序性质。
    • 时间复杂度:O(log n)
    1. 删除堆顶(Pop)
    • 步骤:
      • 交换堆顶与末尾元素,删除末尾。
      • 下沉(Percolate Down):从新堆顶向下比较并交换,直到满足堆序性质。
    • 时间复杂度:O(log n)
    1. 构建堆(Heapify)
    • 最后一个非叶子节点开始 ,逐个下沉调整
    • 时间复杂度:O(n)(非直觉的线性时间)

4、使用heap函数[algorithm头文件]

  • make_heap()

    • 构建最大堆
  • push_heap()

    • 先使用push_back插入元素到末尾
    • 再使用push_heap排序
  • pop_heap()

    • 先使用pop_heap把堆顶放到最后
    • 再用pop_back()删除最后一个元素
cpp 复制代码
#include <algorithm>
#include <vector>

vector<int> v = {3, 1, 4, 1, 5};

// 构建大顶堆
make_heap(v.begin(), v.end()); // [5, 3, 4, 1, 1]

// 插入元素
v.push_back(6);
push_heap(v.begin(), v.end()); // [6, 3, 5, 1, 1, 4]

// 删除堆顶
pop_heap(v.begin(), v.end()); // 将堆顶移到末尾
v.pop_back(); // [5, 3, 4, 1, 1]

三、实现过程

1、构造

  • 默认vector为底层容器
cpp 复制代码
	//默认构造函数
    priority_queue(){}
  • 自定义容器
cpp 复制代码
    //构造函数
    priority_queue(const container& c):data(c){
        make_heap(data.begin(),data.end());
    }//可以指定容器

2、插入

  • 在堆的最后插入新元素
  • 插入完毕后,重新排序
cpp 复制代码
    //插入
    void push(const T& value){
        data.push_back(value);
        push_heap(data.begin(),data.end());
    }

3、删除

  • 删除要先交换堆顶和堆最后一个元素
  • 再进行删除最后一个元素
  • 最后再次排序
cpp 复制代码
    //删除
    void pop(){
        if(!empty()){
            pop_heap(data.begin(),data.end());
            data.pop_back();
        }else{
            throw runtime_error("Priority queue is empty.");
        }
    }

4、查看

  • 访问的堆顶值
cpp 复制代码
    T& top(){
        if(!empty()){
            return data.front();
        }
    }

5、是否为空

  • 为空就是true
  • 否则为false
cpp 复制代码
    bool empty() const{
        return data.empty();
    }

6、大小

  • 返回的数据的个数
cpp 复制代码
    size_t size()const{
        return data.size();
    }

7、完整过程(大顶堆)

cpp 复制代码
template<class T,class container = vector<T>>
class priority_queue{
private:
    container data;
public:
    //默认构造函数
    priority_queue(){}
    //构造函数
    priority_queue(const container& c):data(c){
        make_heap(data.begin(),data.end());
    }//可以指定容器

    //插入
    void push(const T& value){
        data.push_back(value);
        push_heap(data.begin(),data.end());
    }
    //删除
    void pop(){
        if(!empty()){
            pop_heap(data.begin(),data.end());
            data.pop_back();
        }else{
            throw runtime_error("Priority queue is empty.");
        }
    }
    //访问
    T& top(){
        if(!empty()){
            return data.front();
        }
    }
    bool empty() const{
        return data.empty();
    }
    size_t size()const{
        return data.size();
    }
};
int main(){
    // 使用默认底层容器vector
    priority_queue<int>q1;
    q1.push(3);
    q1.push(1);
    q1.push(4);
    q1.push(5);
    cout<<"Top element of q1: "<<q1.top()<<endl;
    q1.pop();
    cout << "Priority queue q1 size after pop: " << q1.size() <<endl;
    //自定义vector
    vector<int>v = {9, 5, 7, 2, 6};
    priority_queue<int,vector<int>>q2(v);
    cout<<"Top element of q2: "<<q2.top()<<endl;
    q2.pop();
    cout<<"Priority queue q2 size after pop: "<<q2.size()<<endl;
}

8、小顶堆

  • 如果要完成小顶堆,就需要逆序排列,可以使用less<typename>的方法来实现。
    • 在template里加入less
    • 在push_heap等等里面,就可以使用less了。
cpp 复制代码
template<class T,class container = vector<T>,class compare = less<T>>
        //小顶堆
class priority_queue{
private:
    container data;
public:
    void push(const T& value) {
        data.push_back(value);
        push_heap(data.begin(), data.end(), compare());
    }
};
相关推荐
身如柳絮随风扬1 分钟前
多数据源切换实战:从业务场景到3种实现方案全解析
java·分布式·微服务
AI科技星3 分钟前
科幻艺术书本封面:《全域数学》第一部·数术本源 第三卷 代数原本(P95-141)完整五级目录【乖乖数学】
算法·机器学习·数学建模·数据挖掘·量子计算
skywalk81633 分钟前
在考虑双轨制,即在中文语法的基础上,加上数学公式的支持,这样像很多计算将更加简单方便,就像现在的小学数学课本里面一样,比如:定x=2*x + 1
开发语言
风筝在晴天搁浅5 分钟前
LeetCode 92.反转链表Ⅱ
算法·leetcode·链表
小书房6 分钟前
Kotlin的by
android·开发语言·kotlin·委托·by
浪客灿心10 分钟前
Linux网络传输层协议
linux·运维·网络
王老师青少年编程19 分钟前
csp信奥赛C++高频考点专项训练之贪心算法 --【贪心与二分判定】:数列分段 Section II
c++·算法·贪心·csp·信奥赛·二分判定·数列分段 section ii
zh_xuan21 分钟前
libcurl调用https接口
c++·libcurl
就叫飞六吧22 分钟前
QT写一个桌面程序exe并动态打包基本流程(c++)
开发语言·c++
蜡笔小马24 分钟前
1.c++设计模式-工厂模式
c++