理解至上:二叉堆与优先队列详细用法

54 篇文章 0 订阅
33 篇文章 2 订阅

二叉堆

概述

为什么不用pq呢
算比较简单的数据结构了
它可以用log的时间复杂度插入元素和访问(取出)最大(小)值(最大和最小只能取一个!)
缺点是除了干这个基本没有别的延伸用法。。。
主要性质(以大根堆为例,小根堆反过来就行):
1.是一棵二叉树(废话
2.爸爸结点永远比儿子大(核心性质)
具体来看看代码实现吧~

插入

先把新元素放在队尾
只要没有到堆顶就不断尝试和爸爸交换;
如果比它的爸爸大,就可以交换

代码

void put(int k){
	tree[++len]=son;//先放在队尾
	int son=len;
	while(son>1){//只要没有到堆顶就不断尝试和爸爸交换:如果比它的爸爸大,就交换
		int fa=son>>1;
		if(tree[fa]>tree[son]) return;//如果比爸爸小的话就可以结束交换了
		swap(tree[fa],tree[son]);
		son=fa;
	}
	return;
}

访问

先取出堆顶的最大值
把当前的队尾填到队首的位置
只要有儿子就不断尝试与儿子交换
如果比儿子中任何一个小,就与其交换

代码

int get(){
	int res=tree[1];//先取出堆顶的最大值
	tree[1]=tree[len--];//把当前的队尾填到队首的位置
	int fa=1;
	while(2*fa<=len){//只要有儿子就不断尝试与儿子交换:如果比儿子中任何一个小,就与其交换
		int son=2*fa;
		if(son<len&&tree[son]<tree[son+1]) son++;//找到较大的那个儿子
		if(tree[son]<tree[fa]) break;
		swap(tree[son],tree[fa]);
		fa=son;
	}
	return res;
}

完整代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const int N=1e5+100;
int tree[N];
int n,len;
int flag,x;
void put(int k){
	tree[++len]=k;//先放在队尾
	int son=len;
	while(son>1){//只要没有到堆顶就不断尝试和爸爸交换:如果比它的爸爸大,就交换
		int fa=son>>1;
		if(tree[fa]>tree[son]) return;//如果比爸爸小的话就可以结束交换了
		swap(tree[fa],tree[son]);
		son=fa;
	}
	return;
}
int get(){
	int res=tree[1];//先取出堆顶的最大值
	tree[1]=tree[len--];//把当前的队尾填到队首的位置
	int fa=1;
	while(2*fa<=len){//只要有儿子就不断尝试与儿子交换:如果比儿子中任何一个小,就与其交换
		int son=2*fa;
		if(son<len&&tree[son]<tree[son+1]) son++;//找到较大的那个儿子
		if(tree[son]<tree[fa]) break;
		swap(tree[son],tree[fa]);
		fa=son;
	}
	return res;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&flag);
		if(flag==1){
			scanf("%d",&x);put(x);
		}
		else printf("%d\n",get());
	}
	return 0;
}

优先队列:priority_queue

基本用法

priority_queue
需要头文件:queue
有这东西写什么二叉树啊
具体用法:

声明:priority_queue q;
插入元素:q.push(x);
访问堆顶:q.top();
弹出堆顶:q.pop();

以下是之前那段代码使用pq的版本:

int main(){
	scanf("%d",&n);
	priority_queue<int>q;
	for(int i=1;i<=n;i++){
		scanf("%d",&flag);
		if(flag==1){
			scanf("%d",&x);
			q.push(x);
		}
		else{
			printf("%d\n",q.top());
			q.pop();
		}
	}
	return 0;
}

简便程度不言而喻

小根堆的声明:

priority_queue<int,vector<int>,greater<int> (注意这里必须有个空格!)> q;

结构体

也可以用结构体,只是需要重载一下运算符 <

struct node{
	int value;
	bool operator < (const node y)const{return value<y.value;};
};
int main(){
	priority_queue<node>q;
	int v;
	node o;
	q.push((node){v});//这里就是看个具体操作的用法,具体怎么操作看你需求啦~
	o=q.front();q.pop();
	return 0;
}

注意

1.当你已经pop完所有元素再取堆顶时,它会一直给你弹出的最后一个
在这里插入图片描述
2.而当你根本没push就直接访问top时,会直接RE

Thanks for reading!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值