Priority_queue

一、priority_queue的介绍和使用

1.1 priority_queue的介绍

1.优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。

2.优先队列类似于堆, 在堆中可以随时插入元素, 并且只能检索最大堆元素(优先队列中位于顶部的元素)。

3.优先队列被实现为容器适配器,容器适配器即将特定的容器类封装作为其底层容器,queue提供一组特定的成员函数来访问其元素,元素从特定容器的尾部弹出,这里称为优先队列的顶部。

4.底层容器可以是任何标准容器类模版,也可以是其他特定设计的容器类,容器应该可以通过随机访问和迭代器访问,需要支持一下操作:

  • empty() : 判断容器是否为空

  • size() : 返回容器中的有效元素个数

  • front() : 返回容器中的第一个元素的引用

  • push_back() : 在容器中尾插元素

  • pop_back() : 在容器中尾删元素

5.标准容器类vector和deque满足这些需求,默认情况下如果没有指定底层容器的话就默认使用vector作为优先队列的底层容器。

6.需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap、和pop_heap来自动完成此操作。

1.2 priority_queue的使用

优先级队列默认使用vector作为求底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以使用priority_queue来替代。

注意:默认情况下,priority_queue是大堆

函数声明接口说明
priority_queue()/priority_queue(first, last)构造一个空的优先级队列
empty()检测优先级队列是否为空,是的话就返回true否则返回false
top()返回优先级队列中最大(最小)的元素,即堆顶元素(默认是大堆,返回最大元素)
push(x)在优先级队列中插入元素x
pop()删除优先级队列中最大(最小)元素,即删除堆顶元素

下面我们来看下优先队列的使用实例:

#include<iostream>
#include<vector>
#include<queue>
//greater算法的头文件
#include<functional>

using namespace std;

void test1()
{
	//默认情况下是建大堆
	priority_queue<int> q1;
	vector<int> arr{ 1, 3, 4, 5, 6 , 7, 9, };
	for (auto& e : arr)
	{
		q1.push(e);
	}
	while (!q1.empty())
	{
		cout << q1.top() << " ";
		q1.pop();
	}
	cout << endl;


	//将第三个模版参数换成great比较方式就是建小堆
	priority_queue<int, vector<int>, greater<int>> q2(arr.begin(), arr.end());
	while (!q2.empty())
	{
		cout << q2.top() << " ";
		q2.pop();
	}
	cout << endl;

}

int main()
{
	test1();


	return 0;
}

二、OJ练习

leetcode215,数组中的第k个最大元素

题目:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们先看题意是让我们找出数组nums中的第k个最大的元素,看到样例2中我们发现相同的数也会被算进k里面,因此我们在这题上面,就可以利用我们的优先级队列,我们将优先级队列中的前k -1 个元素给pop出去,那么剩下的元素中堆顶元素就是我们的第k个最大元素。

下面是这道题的参考代码:

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        priority_queue<int> q1(nums.begin(), nums.end());
        //将前k - 1个元素pop掉就是第k个最大元素
        while(--k) q1.pop();
        //直接返回优先级队列的堆顶元素即可
        return q1.top();
    }
};

三、 priority_queue的模拟实现

3.1 仿函数的概念

仿函数又称为函数对象:重载了operator()的类,类的对象可以向函数一样使用。

operator() 的特点:参数个数和返回值是根据需求定的很灵活。

3.2 仿函数的实现

3.2.1 判断小于的仿函数

下面是我们的判断小于的仿函数的代码:

//判断小于的仿函数
template<class T>
class myless
{
public:
    bool operator() (T& x, T& y)
    {
        return x < y;
    }
};

我们定义了一个重载了operator() 的类,类里面就只有一个重载函数。我们可以通过这种方式来模拟出一个函数。

3.2.2 判断大于的仿函数

下面是我们判断大于的仿函数的代码:

//判断大于的仿函数
template<class T>
class mygreater
{
public:
    bool operator() (T& x, T& y)
    {
        return x > y;
    }
};

这是我们判断大于的仿函数,和判断小于的仿函数的原理相同也是使用了一个类模版,然后再里面重载了一个operator() 函数,用来模拟函数的效果。

3.3 构造以及建堆调整操作

3.3.1 构造函数

这里的构造函数我们先实现默认的无参构造:

//无参构造
priority_queue()
    :c()
    , comp()
{}

将类里面的两个成员变量给一个空值, c是底层容器,comp是用来比较的仿函数。实现建堆的调整函数后我们在来实现我们的迭代器构造函数。

3.3.2 向上调整建堆

下面是我们进行维持优先级队列的顺序的函数之一,向上调整算法:

//向上调整建堆
void Adjust_up(int child)
{
    int parent = (child - 1) / 2;
    while (child > 0)
    {
        //if (c[parent] < c[child])
        if(comp(c[parent], c[child]))
        {
            swap(c[parent], c[child]);
        }
        child = parent;
        parent = (child - 1) / 2;
    }
}

我们首先要知道用数组模拟堆,也就是优先级队列,它的子节点和父亲节点的下标之间的关系,在向上建堆操作中我们是从下往上的,我们需要知道parent和child之间的关系,它们之间的关系就是 parent = (child - 1) / 2 , 这里的比较我们可以使用仿函数来比较也可以直接实用大于和小于号比较但是建议使用仿函数,因为仿函数的通用性高, 当我们的父节点小于我们的子节点时我们就将他们交换位置,然后将父节点的位置给到子节点,然后重新计算父节点,相当于是更新子节点和父节点。

3.3.3 向下调整建堆

下面是我们的向下调整算法:

//向下调整建堆
void Adjust_down(int parent)
{
    int child = parent * 2 + 1;
    if (child + 1 < c.size() && c[child] < c[child + 1])
    {
        child++;
    }
    while (child < c.size())
    {
        //if (c[parent] < c[child])
        if(comp(c[parent], c[child]))
        {
            swap(c[parent], c[child]);
        }
        parent = child;
        child = parent * 2 + 1;
    }
}

向下建堆的效率要比向上调整建堆的效率要高很多, 在我们的迭代器区间构造和我们的pop函数中可以使用我们的向下调整算法来维持优先队列的结构。原理和向上调整建堆基本相同,向下调整算法是传入parent的值,然后计算出child的值,child和parent的关系式是:child = parent * 2 + 1, 然后我们选出最大的左右子节点中较大的那个子节点,对parent和child进行比较,如果parent的值小于child的值的话就将它们调换位置,然后将child的下标给给parent,然后再计算child的下标,相当于更新位置。

3.3.4 使用迭代器区间进行构造

下面是我们的实例代码:

 //迭代器区间构造
 template <class InputIterator>
 priority_queue(InputIterator first, InputIterator last)
     :c()
     ,comp()
 {
     while (first != last)
     {
         c.push_back(*first);
         first++;
     }

     for (int i = (c.size() - 1 - 1) / 2; i >= 0; i--)
     {
         Adjust_down(i);
     }
     
 }

这里我们直接将这个迭代器区间中的值通过迭代器遍历逐个放进我们的底层容器中即可,然后通过我们的向下调整算法进行建堆。

3.4 priority_queue中的容量以及访问访问修改操作

3.4.1 容量相关的接口

我们容量相关的接口有size和empty,size的作用是返回有效数据的个数,empty的作用是判断队列中是否为空。

下面来看我们的size接口:

//返回有效数据个数
size_t size() const
{
    return c.size();
}

对于我们的size接口就直接返回我们底层容器的size接口的值即可。

再来看下我们的empty接口:

 //判断优先队列里面是否为空
 bool empty() const
 {
     return c.empty();
 }

与size接口同理empty接口也是直接返回我们的底层容器的接口即可。

3.4.2 访问和修改

关于访问和修改操作的接口有:top, push, pop

下面依次来看这些接口:

top:

 //返回队头元素
 T& top() 
 {
     return c[0];
 }
 const T& top() const
 {
     return c[0];
 }

top 接口的作用是返回我们的队头元素,我们的底层容器是动态数组vector我们就直接返回数组的第一个元素即可。

push:

//入队操作
//尾插入队,执行向上调整操作
void push(const T& x)
{
    c.push_back(x);
    Adjust_up(c.size() - 1);
}

对于入队操作我们直接尾插进数组即可,尾插之后执行向上调整操作。

pop:

//出队操作
//先交换最后一个元素和第一个元素的位置
//尾删出队,执行向下调整操作
void pop()
{
    swap(c[0], c[size() - 1]);
    c.pop_back();
    Adjust_down(0);
}

对于我们pop接口的作用时将堆顶元素给pop出去,我们将堆顶元素和数组最后一个元素进行交换位置,然后进行尾删,最后执行向下调整操作,维持堆的结构即可。


这就是这篇文章的全部内容了,希望大家能从以上内容中对优先级队列有一定的理解。


对于入队操作我们直接尾插进数组即可,尾插之后执行向上调整操作。

pop:

```C++
//出队操作
//先交换最后一个元素和第一个元素的位置
//尾删出队,执行向下调整操作
void pop()
{
    swap(c[0], c[size() - 1]);
    c.pop_back();
    Adjust_down(0);
}

对于我们pop接口的作用时将堆顶元素给pop出去,我们将堆顶元素和数组最后一个元素进行交换位置,然后进行尾删,最后执行向下调整操作,维持堆的结构即可。


这就是这篇文章的全部内容了,希望大家能从以上内容中对优先级队列有一定的理解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/683367.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

React中使用 ts 后,craco库配置别名时需要注意什么?

文章目录 前言编译报错如下解决方式总结 前言 我们都知道craco库可以用来覆盖react配置&#xff0c;如设置别名等。但是在项目使用 Typescript 后&#xff0c;我们需要额外配置&#xff0c;否则会造成编译报错。 详细craco配置可以查看之前文章&#xff1a; 项目初始化与配置…

SpringBoot:SpringBoot中使用Redisson实现分布式锁

一、前言 Redisson是一个在Redis的基础上实现的Java驻内存数据网格&#xff08;In-Memory Data Grid&#xff09;。它不仅提供了一系列的分布式的Java常用对象&#xff0c;还提供了许多分布式服务。 刚好项目中需要使用到分布式锁&#xff0c;记录一下Redisson是如何使用分布式…

PHP 页面报错Warning</b>: Cannot modify header information - headers already sent by

先给出解决方案再解释&#xff0c;如果急着用就不用看解释了。 解决方案一&#xff1a;保存php文件编码为utf-8无BOM码&#xff0c;具体操作可以用notepad等编辑器完成&#xff0c;把 sesstion_start() 放在文档所有输出&#xff08;包括html标签和php的输出语句&#xff0c;具…

场外个股期权标的有哪些?

今天带你了解场外个股期权标的有哪些&#xff1f;场外个股期权是一种金融衍生品&#xff0c;它不在交易所内进行交割&#xff0c;而是在交易所以外的场所进行交易的股票期权合约。 场外个股期权标的有哪些&#xff1f; 场外个股期权的标的通常包括A股市场上的融资融券标的&…

掌握Django文件处理:一步步构建上传功能

创建模型 首先先进入我们的testsite项目下&#xff0c;打开members/models.py文件&#xff0c;先添加我们保存文件的数据模型&#xff1a; class Document(models.Model):name models.CharField(max_length255)file models.FileField(upload_touploads/) # uploads/ 是文件…

批量提取 Word 文档中的全部图片

步骤 1、打开 WinRAR 任选一个现成的压缩包双击打开 WinRAR &#xff0c;或从开始菜单打开 WinRAR 2、直接把要提取图片的 Word 文档拖入 WinRAR 菜单区域 1 → 2 → 3&#xff0c;WinRAR 资源管理目录中的 media 就是该 Word 文档所要提取的全部图片所在文件夹 按住&#x…

【Vue】异步更新 $nextTick

文章目录 一、引出问题二、解决方案三、代码实现 一、引出问题 需求 编辑标题, 编辑框自动聚焦 点击编辑&#xff0c;显示编辑框让编辑框&#xff0c;立刻获取焦点 即下图上面结构隐藏&#xff0c;下面结构显示&#xff0c;并且显示的时候让它自动聚焦。 代码如下 问题 “…

Vue3:eachars 折线图 数据不联动 和 tooltip: trigger: ‘axis‘ 不生效,不提示数据

问题1&#xff1a; 点击折线图的头部数据&#xff08;Email、UnionAds等&#xff09; 下面数据线不联动问题 问题2&#xff1a;下图是没有提示数据的Demo 这是echars官网的提示数据图 3.解决办法 &#xff08;1&#xff09;检查是否设置&#xff1a;trigger&#xff1a;axi…

SELinux深度解析:安全增强型Linux的探索与应用(下)

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Linux &#xff1a;从菜鸟到飞鸟的逆袭》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、SELinux的工作机制 1、SELinux的三种状态&#xff1a;Pe…

在k8s中部署Kafka高可用集群超详细讲解

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《数据流专家&#xff1a;Kafka探索》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、Kafka简介 2、为什么在Kubernetes中部署Kafka 二、…

决策树Decision Tree

目录 一、介绍发展优点缺点基本原理 二、熵1、熵2、条件熵3、信息增益4、信息增益率 三、基尼系数四、ID3算法1、建树过程2、优点3、缺点 五、C4.51、二分法处理连续变量1、流程&#xff1a;2、示例 2、缺点 六、CART1、连续数据处理2、离散数据处理3、CART回归原理1、均方误差…

医学编码系统说明

简介 流程说明 登录系统 在浏览器中访问FNEHR的站点&#xff0c;输入医院编号、用户和密码&#xff0c;选择“Other”&#xff0c;点击“Login”按钮&#xff0c;登录系统&#xff1a; 登录后&#xff0c;在左边显示系统的菜单&#xff1a; 系统设置 医院设置 点击左侧的“Acc…

尚硅谷2024新版3小时速通Docker教程

尚硅谷2024新版3小时速通Docker教程 百度网盘&#xff1a;https://pan.baidu.com/s/1SncgHbdJehvZspjcrrbLSw?pwd6c27

【C语言】详解函数(下)(庖丁解牛版)

文章目录 1. 前言2. 数组做函数形参3. 函数嵌套调用和链式访问3.1 嵌套调用3.2 链式访问 1. 前言 详解C语言函数(上)的链接&#xff1a;http://t.csdnimg.cn/EGsfe 经过对函数的初步了解之后,相信大家已经对C语言标准库里的函数已经有初步的认知了&#xff0c;并且还学会了如…

【工具箱】嵌入式系统存储芯片——CS创世 SD NAND

大家都知道MCU是一种"麻雀"虽小&#xff0c;却"五脏俱全"的主控。它的应用领域非常广泛&#xff0c;小到手机手表&#xff0c;大到航空航天的设备上都会用到MCU.市面上目前几个主流厂商有意法半导体&#xff08;其中最经典的一款就是STM32系列&#xff09;…

足球俱乐部管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;教练管理&#xff0c;用户管理&#xff0c;合同信息管理&#xff0c;赛事管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;公告信息&#xff0c;赛事…

C++ STL - 容器

C STL&#xff08;标准模板库&#xff09;中的容器是一组通用的、可复用的数据结构&#xff0c;用于存储和管理不同类型的数据。 目录 零. 简介&#xff1a; 一 . vector&#xff08;动态数组&#xff09; 二. list&#xff08;双向链表&#xff09; 三. deque&#xff08…

Ansible部署 之 zookeeper集群

简介 Ansible是近年来越来越火的一款轻量级运维自动化工具&#xff0c;主要功能为帮助运维实现运维工作的自动化、降低手动操作的失误、提升运维工作效率。常用于自动化部署软件、自动化配置、自动化管理&#xff0c;支持playbook编排。配置简单&#xff0c;无需安装客户端&am…

LNMP网络架构的搭建

操作准备&#xff1a;准备三台虚拟机 安装 MySQL 服务 &#xff08;1&#xff09;准备好mysql目录上传软件压缩包并解压 cd /opt mkdir mysql tar xf mysql-boost-5.7.44.tar.gz &#xff08;2&#xff09;安装mysql环境依赖包 yum -y install ncurses ncurses-devel bison…

idea 中:运行 Application 时出错。命令行过长

一、问题描述&#xff1a; idea 导入新项目&#xff0c;在编译后&#xff0c;运行项目时&#xff0c;报以下错误&#xff1a; 14:47 运行 Application 时出错运行 Application 时出错。命令行过长。通过 JAR 清单或通过类路径文件缩短命令行&#xff0c;然后重新运行。二、问题…