优先级队列--priority_queue

本文介绍了C++中的优先级队列priority_queue,它是基于堆实现的容器适配器,用于每次出队时返回当前队列的最大值。文章详细讲解了priority_queue与普通队列的区别、堆的概念、以及priority_queue的实现和操作,包括push、pop、top等函数的工作原理。
摘要由CSDN通过智能技术生成

适配器

适配器简单的来说就是一种设计模式,C++的STL中的大部分模板都有着相似的功能,与相同的接口函数名,类似于这样的:

  • push_back(); pop_back(); push_front(); pop_front();
  • size(); empty();

所以说对于这种类型的容器,就可以对他们进行封装,从而实现一些列的功能,就比如说:

  • stack,queue
  • deque,priority_queue

在这里插入图片描述
虽然对于队列和栈,我们也可以用一些数据结构来实现,但是他们的功能STL中的其他容器都具备,所以STL中并没有将stack和queue划分在容器这一类,而是用了一个容器适配器。

有了容器适配器,我们就可以根据不同的使用场景来确定使用不同的容器

  • 经常要头插元素的话,我们就可以使用list当做适配器的类型,因为他的底层是一个带头结点的双向循环链表,头插时间复杂度是O(1)
  • 如果要经常访问元素的话,我们就可以使用vector作为适配器的类型,他的底层是一个数组,数组对于访问的时间复杂度是O(1)
  • 在STL中他是用一个双端队列deque来实现的,他结合了list插入效率高,以及vector访问效率高的特点。但是他却不适合遍历,他的内部是一段一段的有长度的地址区间,每一次访问都需要检测是否越界,所以遍历有些困难。

priority_queue

priority_queue,翻译过来就是优先队列的意思。
在这里插入图片描述
他是一个封装在queue中的一个容器适配器,底层默认是用vector来实现,并且默认是降序,也就是默认是一个大堆。

与队列的不同点

队列作为一个先进先出的标准数据模型,它内部的数据不能保证有序。

STL基于这一特点,对queue做了改进,让他每一次出队的数据保证是当前队列的最值(最大值,最小值),但是却不满足了先进先出的特点。

因为优先队列需要满足每次front()都是队列的最值,还有不停的插入元素,那么单纯的用sort()函数进行排序是不行的,因为他每一次的时间复杂度都是O(n * log(n))
这个时候就可以使用堆,建一个大根堆或者小根堆,每一次获取队头元素都是堆顶的元素,都是可以保证是最值,而且插入删除再次建堆的时间复杂度也只是O(log(n))

priority_queue实现的功能

  • pushk();,尾插一个数据 ,内部进行向上建堆
  • pop();,删除队头数据,也就是队列中的一个最值,然后内部进行向下建堆
  • top();,返回队列中头部元素,也就是队列中的最值
  • size();,返回队列中元素的数量
  • empty();,判断队列是否为空

复习一下堆

堆是一种特殊的二叉树结构,他的每一个根节点都是这棵子树的一个最值(最大值或者最小值)

  • 根节点是最大值,这是一个大根堆
  • 根节点是最小值,这是一个小根堆

他的存储可以用一个数组来实现,不必建一个二叉树。这里有一个注意的点就是:(假设父亲节点为parent)

  • 当你选择的第一个元素的下标为0,那么他的左孩子节点就是parent * 2 + 1
  • 如果选择第一个元素下标为1,那么他的左孩子节点就是parent * 2

说到这个不禁想起上学期期末的数据结构考试,考试之前自己实现了一下堆,当时用的是数组嘛,下标都是从0开始的,这样求左孩子节点是parent * 2 + 1

考试的时候问了二叉树的左孩子节点,想都没想,直接parent * 2 + 1,事后才发现,二叉树根节点是按照1算的,也就是parent * 2

图解堆删除元素的过程

画图的步骤我就不好意思的用leetcode上的可视化来显示了
在这里插入图片描述

  • 以一个大根堆为例,这是一开始的结构
    在这里插入图片描述
  • 每一次比较删除之后

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

堆的向下调整,对应pop

  • 向下调整一般是建立在删除或者排序的时候,这里因为vector数组的原因,删除的时候选择先交换,再删除末尾元素。因为删除开始位置的元素开销太大
  • 向下调整的开始点一般在根节点的位置
//向下调整,数组默认以0开始
void AdjestDown(vector<int> arr,int parent)
{
   
	size_t child = parent * 2 + 1;
	size_t len = arr.size();

	while (child < len)
	{
   
		//找左右孩子中最大的
		if (child + 1 < len && arr[child]< arr[child + 1
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值