数组模拟堆模板

1.插入一个数
添加头结点比较困难,添加尾结点十分容易

heap[++size]=x;
up(size);

2.求集合中的最小值

heap[1];

3.删除最小值
删除头结点非常困难,删除尾结点非常方便

heap[1]=heap[size];
size--;
down(1);

4.删除任意元素


heap[k]=heap[size];
size--;

down(k);//只有heap[k]变大时执行
up(k);//只有heap[k]变小时执行

5.修改任意元素

heap[k]=x;
down(k);
up(k);

注意:
1.下标从1开始,比较方便,x=0时,2x=0;
2.4,5仅数组模拟的堆可实现,STL实现不了)
堆是一棵完全二叉树

小根堆:每一点小于等于左右儿子

堆的存储结构:
1是根结点
对于结点x:
左儿子为2x,右儿子为2x+1

基本操作:
1.up
2.down
两个操作的时间复杂度都与树的高度有关logn

void down(int k){

}

建堆:
法1.一个一个往里插,总共时间复杂度O(nlogn)
法2.从n/2down到1,时间复杂度为O(n)

for(int i=n/2;i>=1;i--){
   down(i);
}

ph[k]第k个插入的点在堆里的下标
hp[j]堆里j点是第几个插入的点

ph[k]=j;
hp[j]=k;

例题:堆排序

在这里插入图片描述

#include <iostream>
#include <algorithm>
using namespace std;
const int N=100010;
int h[N],s;
void down(int i){
    int u=i;
    if(2*i<=s&&h[u]>h[2*i]){
        u=2*i;
    }
    if(2*i+1<=s&&h[u]>h[2*i+1]){
        u=2*i+1;
    }
    
    if(u!=i){
        swap(h[u],h[i]);
        down(u);
    }
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    s=n;
    
    for(int i=1;i<=n;i++){
        scanf("%d",&h[i]);
    }
    
    for(int i=n/2;i>=1;i--){
        down(i);
    }//初始化堆
    
    while(m--){
        printf("%d ",h[1]);
        h[1]=h[s];
        s--;
        down(1);
    }
    return 0;
}

例题:模拟堆

在这里插入图片描述

#include <iostream>
#include <cstring>
using namespace std;
const int N=100010;
int h[N],hp[N],ph[N];
//ph[k]第k个插入的值的下标
//hp[i]下标为i的值是第k个插入的
int s=0;
void swap_(int l,int r){
   swap(h[l],h[r]);
   swap(hp[l],hp[r]);
   swap(ph[hp[l]],ph[hp[r]]);
}
void down(int i){
    int u=i;
    if(2*i<=s&&h[u]>h[2*i])u=2*i;
    if(2*i+1<=s&&h[u]>h[2*i+1])u=2*i+1;
    if(u!=i){
        swap_(u,i);down(u);
    }
    
}
void up(int i){
    while(i/2&&h[i]<h[i/2]){
        swap_(i,i/2);
        i=i/2;
    }
    
    
}


int main(){
    int n,m=0;//m表示当前是第几个插入的数
    scanf("%d",&n);
    while(n--){
        char op[5];
        scanf("%s",op);
        if(!strcmp(op,"I")){
            int x;
            scanf("%d",&x);
            
            m++;
            s++;
            h[s]=x;
            
            hp[s]=m;
            ph[m]=s;
            
            up(s);
            
        }else if(!strcmp(op,"D")){
            int k;
            scanf("%d",&k);
            k=ph[k];//转化成堆里的下标
            swap_(k,s);
            s--;
            up(k),down(k);//这两个函数最多只会执行其中一个
            
        }else if(!strcmp(op,"C")){
            int k,x;
            scanf("%d%d",&k,&x);
            k=ph[k];
            h[k]=x;
            down(k), up(k);
            
            
            
        }else if(!strcmp(op,"PM")){
            printf("%d\n",h[1]);
        }else{
            swap_(1,s);
            s--;
            down(1);
            
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值