[YM]模板-堆

概念:

堆是一种树形结构,堆顶始终是最优值(最大或最小)

堆一般是用二叉树实现的,称为二叉堆

二叉堆是一种完全二叉树

堆由对顶可以分为大根堆小根堆 

————————————————————————————————

堆一般用数组去实现:

用数组A[ ]存储完全二叉树,节点数量是n,A[1]为根节点,有以下性质

1i>1的节点,其父节点位于i/2

2)如果2i>n,那么节点i没有孩子;如果2i+1>n,那么节点i没有右孩子

3)如果节点i有孩子,那么他的左孩子是2i,右孩子是2i+1

堆有两种操作:进堆和出堆

priority_queue优先队列默认是大根堆

————————————————————————————————

模板:

struct Heap{
    int data[N]={0},len=0;
    void push(int e){
        data[++len]=e;
        int i=len;
        while(i>1&&data[i]<data[i/2]){
            swap(data[i],data[i/2]);
            i/=2;
        }
    }
    void pop(){
        data[1]=data[len--];
        int i=1;
        while(2*i<=len){
            int son=2*i;
            if(son<len&&data[son+1]<data[son])son++;
            if(data[son]<data[i]){
                swap(data[son],data[i]);
                i=son;
            }
            else break;
        }
    }
    int top(){
        return data[1];
    }
};

push详解:

void push(int x) {      //上浮,插入新元素
	heap[++len] = x;   //堆尾加入元素
	int i = len;       
	while (i > 1 && heap[i] < heap[i / 2]) {       //和它的父节点比较
		swap(heap[i], heap[i / 2]);
		i /= 2;    //更新父节点
	}
}

pop详解:

void pop() {     //下沉,删除推头,调整堆
	heap[1] = heap[len--];     //根节点替换为最后一个节点,节点数减一
	int i = 1;
	while (2 * i <= len) {      //至少有一个左儿子
		int son = 2 * i;         //左儿子
		if (son < len && heap[son + 1] < heap[son])  
			son++;       //son<len表示有右儿子,选儿子中较小的一个
		if (heap[son] < heap[i]) {      
			swap(heap[son], heap[i]);  //与较小的儿子交换
			i = son;      //下沉到儿子处
		}
		else break;       //如果不比儿子小,就停止下沉
	}
}

例题:

洛谷:P3378 【模板】堆 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

代码:

/*---code---*/
const int N = 1e6 + 5;
struct Heap{
    int data[N]={0},len=0;
    void push(int e){
        data[++len]=e;
        int i=len;
        while(i>1&&data[i]<data[i/2]){
            swap(data[i],data[i/2]);
            i/=2;
        }
    }
    void pop(){
        data[1]=data[len--];
        int i=1;
        while(2*i<=len){
            int son=2*i;
            if(son<len&&data[son+1]<data[son])son++;
            if(data[son]<data[i]){
                swap(data[son],data[i]);
                i=son;
            }
            else break;
        }
    }
    int top(){
        return data[1];
    }
};
Heap hp;
void solve(){
	int q;cin>>q;
    while(q--){
        int op,x;
        cin>>op;
        if(op==1){
            cin>>x;
            hp.push(x);
        }else if(op==2){
            cout<<hp.top()<<"\n";
        }else{
            hp.pop();
        }
    }
}

STL库的priority_queue

priority_queue本身是大根堆,我们重载一下变成小根堆

小根堆:priority_queue<int,vector<int>,greater<int>>hp;

大根堆:priority_queue<int>hp;

/*---code---*/
const int N = 1e6 + 5;
priority_queue<int,vector<int>,greater<int>>hp;
void solve(){
	int q;cin>>q;
    while(q--){
        int op,x;
        cin>>op;
        if(op==1){
            cin>>x;
            hp.push(x);
        }else if(op==2){
            cout<<hp.top()<<"\n";
        }else{
            hp.pop();
        }
    }
}

  • 13
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值