数据结构--二叉堆与优先队列

堆的一些性质

1、堆是一颗完全二叉树

2、堆的顶端一定是“最大”/最小”的,但是要注意一个点,这里的大和小并不是传统意义下的大和小,它是相对于优先级而言的.

3.堆一般有两种样子,小根堆和大根堆,分别对应第二个性质中的“堆顶最大”“堆顶最小”,对于大根堆而言,任何一个非根节点,它的优先级都小于堆顶,对于小根堆而言,任何一个非根节点,它的优先级都大于堆顶
在这里插入图片描述
4、操作:

插入一个元素

取得最小(最大)的数值,并且删除
  
  能够完成这种操作的数据结构叫做优先队列

而能够使用二叉树,完成这种操作的数据结构叫做堆(二叉堆)

5、堆与优先队列的时间复杂度:

若共有n个元素,则可在O(logn)的时间内完成上述两种操作

优先队列

STL中的优先队列就是采用大根堆来实现的。

//优先队列需要头文件 
#include<queue> 
// 定义优先队列 
priority_queue<结构类型> 队列名; 
priority_queue <int> q; 
priority_queue <double> d; 
//优先队列的操作 
q.size();//返回q里元素个数 
q.empty();//返回q是否为空,空则返回1,否则返回0 
q.push(k);//在q的末尾插入k 
q.pop();//删掉q的第一个元素 
q.top();//返回q的第一个元素

例1:合并果子

less和greater优先队列

priority_queue <int,vector<int>,less<int> > p; 
priority_queue <int,vector<int>,greater<int> > q;

less从大到小, greater是从小到大
【代码】

#include<bits/stdc++.h>
using namespace std;
int n,x,ans;
priority_queue<int,vector<int>,greater<int> >q;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>x,q.push(x);
	while(q.size()>=2){
		int a=q.top(); q.pop();
		int b=q.top(); q.pop();
		ans+=a+b;
		q.push(a+b);
	}
	cout<<ans<<endl;
	return 0;
}

结构体优先队列

要想使用结构体的优先队列, 需要在结构体内部重载小于号

struct node 
{ 
  int x,y; 
  bool operator < (const node & a) const 
 { 
    return x<a.x; 
 } 
};

一个node 结构体有两个成员,x 和y ,它的小于规则是 x小者小。
它也是按照重载后的小于规则,从大到小排序的。

priority_queue <node> q;
int main()
{
  k.x = 10, k.y = 100; q.push(k);
  k.x = 12, k.y = 60; q.push(k);
  k.x = 14, k.y = 40; q.push(k);
  k.x = 6, k.y = 80; q.push(k);
  k.x = 8, k.y = 20; q.push(k);
  while (!q.empty())
 {
    node m = q.top(); q.pop();
    printf("(%d,%d) ", m.x, m.y);
 }
}

程序大意就是插入 这五个node,再来看看它的输出:
(14,40) (12,60) (10,100) (8,20) (6,80)
就是按照 x从大到小排序的.

优先队列

例题2:最高的奖励
【解析】
我们先准备完成所有的任务,直到出现冲突,我们再放弃某个任务。在必须要放弃任务时,我们尽量选择奖励低的任务放弃。所以我们先将任务按照结束时间排序,早结束的放在前面,然后逐个将任务加入到优先队列,一旦出现结束时间为 ,而优先队列中的任务数量大于 的情况,则放弃奖励最低的任务。
【代码】

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+10;
struct node{
	LL x,val;
}a[N];
bool cmp(struct node a,struct node b)
{
	return a.x<b.x;
}
int main()
{
	int n;
	LL ans=0;
	cin>>n;
	for(int i=0;i<n;i++)cin>>a[i].x>>a[i].val;
	sort(a,a+n,cmp);
	priority_queue<int,vector<int>,greater<int> > Q;
	for(int i=0;i<n;i++)
{
	if(a[i].x>Q.size())
	{
		Q.push(a[i].val);
		ans+=a[i].val;
	}
	else
	{
		LL w=Q.top();
		
		if(a[i].val>w)
		{
		Q.pop();
		Q.push(a[i].val);
		ans=ans-w+a[i].val;
		}
	}
}
	cout<<ans<<endl;
}

课后练习

1、卡车加油
2、小b浇花

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信奥教练Andy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值