【数据结构】堆

堆 Heap

  • 完全二叉树:在二叉树中,若当前节点的下标为 i i i, 则其父节点的下标为 i / 2 i/2 i/2,其左子节点的下标为 i ∗ 2 i*2 i2,其右子节点的下标为 i ∗ 2 + 1 i*2+1 i2+1
  • 某个节点的值总是不大于或不小于其父节点的值
    • 大根堆:父亲不小于儿子
    • 小根堆:不大于

构建大根堆

  • 从最后的子树开始 判断是不是最大的是爹

  • 在这里插入图片描述

  • 然后从下向上构建每个子树

vector<int>maxheap(n+1);
void MaxHeapInit(){
    int len=maxheap.size();//maxheap用vector存的
    int fa;
    reforr(i,1,len/2){//从最后一个节点的爹开始

        fa=maxheap[i];//fa是本次子树的爹
        int son=i*2;//本次爹的左儿子

        while (son<=len)
        {
            if(son<len&&maxheap[son]<maxheap[son+1])son++;//看右儿子是不是比左大 左右儿子和爹之中,最大的应该做爹
            //son此时指向最大的儿子
            if(fa>=maxheap[son])break;//爹比儿子大 不换
            else{
                //爹小了
                maxheap[son/2]=maxheap[son];//儿子上浮
                son*=2;//找儿子的儿子能不能上浮
            }
        }
        maxheap[son/2]=fa;//本次儿子小于爹,把爹放到本次儿子的爹 归位
    }
}

插入

  • 堆的最后添加一个节点,然后沿着堆树上升
void insert(int x){
    maxheap.push_back(x);//放到最后
    int len=maxheap.size();
    int son=len;
    while (son>=1&&x>maxheap[son/2-1])//比爹大就换
    {
        maxheap[son-1]=maxheap[son/2-1];//爹下移
        son/=2;
    }
    maxheap[son-1]=x;
}

删除

  • 堆中每次只能删堆顶元素
    小根堆
  • 删除堆顶后把最后子节点放到堆顶位置然后下移
    在这里插入图片描述
void delete(){
    int len=maxheap.size();
    int x==maxheap[len-1];//最后一个子节点上移
    int i=1,son=i*2;
    while(son<=len){
        if(son<=len&&x<maxheap[son])son++;//如果小于右树 优先向右树下移
        if(x>=maxheap[son-1])break;
        maxheap[i-1]=maxheap[son-1];
        i=son;
        son*=2;
    }
    maxheap[i]=x;
}

堆排序

  • 无序数组->二叉堆
  • 时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn) 不稳定排序

排序稳定性:排序后 2 个相等键值的顺序和排序之前它们的顺序相同

步骤

  • 构造大根堆(升序)/小根堆(降序)
    在这里插入图片描述

  • 每次交换堆顶和最后一个元素,使堆顶元素(剩下中最大数)归位。

  • 然后再构建根堆

void MaxHeapInit_range(int end){
    int len=end;
    int fa;
    reforr(i,1,len/2){
        fa=maxheap[i];
        int son=i*2;
        while (son<=len)
        {
            if(son<len&&maxheap[son]<maxheap[son+1])son++;
            if(fa>=maxheap[son])break;
            else{
                maxheap[son/2]=maxheap[son];
                son*=2;
            }
        }
        maxheap[son/2]=fa;
    }
}
void heap_sort(){
    int len=maxheap.size()-1;
    reforr(i,1,len){
        //display();
        MaxHeapInit_range(i);
        swap(maxheap[1],maxheap[i]);
    }
}
void solve(){
    maxheap.push_back(0);
    int n=7;
    forr(i,1,n){
        int num;
        cin>>num;
        maxheap.push_back(num);
    }
    heap_sort();
    display();
}

priority_queue

  • 底层二叉堆实现
  • 头文件#include<queue>
priority_queue<int>q;//默认大根堆
priority_queue<int,vector<int>,greater<int>>q;//小根堆
  • 对结构体排序时,需要先定义比较符号
    • 大根堆:小于号
      struct pos{
          int x,y;
          bool operator<(const pos&a)const{
              return x<a.x;
          }
      };
      
    • 小根堆:大于号
      struct pos{
          int x,y;
          bool operator>(const pos&a)const{
                  return x>a.x;
              }
      };
      priority_queue<pos,vector<pos>,greater<pos>>q;
      

P1090 合并果子

思路

  • 贪心:每次选择最少的两个堆合并
  • 用堆/优先队列

代码

之后填坑…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值