【c++】【STL】priority_queue详解

目录

  • priority_queue的作用
  • priority_queue的接口
    • 构造函数
    • empty
    • size
    • top
    • push
    • pop
    • swap
  • priority_queue的实现
    • 仿函数(函数对象)是什么?
    • 向上调整算法(adjustup)
    • 向下调整算法(adjustdown)
    • 迭代器构造
    • push
    • pop

priority_queue的作用

priority_queue翻译过来就是优先级队列,是stl提供的一个容器适配器,也就是我们数据结构中学到的栈,是一种常用的数据结构,特点是利用类似二叉树的结构让父节点元素比子节点大,从而使对顶元素最大(小)。

priority_queue的接口

构造函数

explicit priority_queue (const Compare& comp = Compare(),const Container& ctnr = Container());
template <class InputIterator>priority_queue (InputIterator first, InputIterator last,const Compare& comp = Compare(),const Container& ctnr = Container());

可以用默认构造和迭代器构造,支持指定容器和仿函数对象。

empty

bool empty() const;

堆的判空。

size

size_type size() const;

返回堆的元素数。

top

const value_type& top() const;

返回堆顶元素。

push

void push (const value_type& val);

入堆。

pop

void pop();

出对顶的元素。

swap

void swap (priority_queue& x) noexcept (/*see below*/);

priority_queue自己的交换函数。

priority_queue的实现

#include<iostream>#include<vector>using namespace std;namespace jiunian
{template<class T, class container = vector<T>, class compare = less<T>>class priority_queue{public:typedef priority_queue<T, container> Self;priority_queue(){}template<class Iterator>priority_queue(Iterator begin, Iterator end){Iterator cur = begin;while (cur != end) con.push_back(*(cur++));int pos = size() / 2 - 1;while (pos >= 0) adjustdown(pos--);}bool empty() const{return con.empty();}size_t size() const{return con.size();}const T& top() const{return con.front();}void push(const T& val){con.push_back(val);adjustup(con.size() - 1);}void pop(){std::swap(con.front(), con.back());con.pop_back();adjustdown(0);}void swap(priority_queue& x){con.swap(x.con);}Self operator=(Self x){con = x.con;comp = x.comp;return *this;}private:void adjustdown(int pos)//向下调整{int parent = pos;int child = parent * 2 + 1;if (child + 1 < con.size() && comp(con[child] , con[child + 1])) ++child;while(child < con.size()){if (comp(con[parent], con[child])){std::swap(con[child], con[parent]);parent = child;child = parent * 2 + 1;if (child + 1 < con.size() && comp(con[child], con[child + 1])) ++child;}else{break;}}}void adjustup(int pos)//向上调整{int child = pos;int parent = (child + 1) / 2 - 1;while (parent >= 0){if (comp(con[parent], con[child])){std::swap(con[child], con[parent]);child = parent;parent = (child + 1) / 2 - 1;}else{break;}}}container con;compare comp;};
}

仿函数(函数对象)是什么?

仿函数又称函数对象,是指其本质虽然是对象,但是用起来就像函数一样,一个简单的仿函数长下面这样:

template<class T>
class compareruler
{bool operator()(const T& a, const T& b){return a < b;}
};

仿函数通过重载()运算符使其使用起来就像函数一样,依旧以上面这个仿函数为例,它的用法如下

	compareruler<int> com;int a = 0;int b = 1;cout << com(a, b) << endl;

不看上面的对象初始化就会误以为com是函数了。这就是仿函数,那说了这么多,仿函数有什么用呢?学习过模板的都知道,c++提倡泛型编程,即一段代码多种用途,通过模板与模板实例化使一段代码生成多段代码,鼓励用户自定义,提高编程效率。而仿函数更是使泛型编程更进一步,仿函数可以自定义模板编程中的策略模式,使用户使用起来更加自由,比如在堆的实现过程中就可以自定义两数之间的比较交换规则实现大堆小堆的切换,这也是我提前介绍一下仿函数的原因。

向上调整算法(adjustup)

void adjustup(int pos)//向上调整
{int child = pos;int parent = (child + 1) / 2 - 1;while (parent >= 0){if (comp(con[parent], con[child])){std::swap(con[child], con[parent]);child = parent;parent = (child + 1) / 2 - 1;}else{break;}}
}

向上调整算法是堆的核心算法之一,其原理是将指定元素通过与其父结点比较,若不符合当前堆的排列规则(大堆小堆)就交换,符合就停止,不断地循环这个过程直到根节点,从而将指定元素排到合适的位置。具体的实现过程就是先指定结点,将指定的结点视为子节点,算出子结点的父节点,将两者进行比较,比较逻辑由仿函数给出。若仿函数返回true就交换,之后将换完的父节点视为子节点,再次计算父节点不断循环;若仿函数返回false就说明到合适的位置了,停止循环即可。过程中要时刻注意越界问题。

向下调整算法(adjustdown)

void adjustdown(int pos)//向下调整
{int parent = pos;int child = parent * 2 + 1;if (child + 1 < con.size() && comp(con[child] , con[child + 1])) ++child;while(child < con.size()){if (comp(con[parent], con[child])){std::swap(con[child], con[parent]);parent = child;child = parent * 2 + 1;if (child + 1 < con.size() && comp(con[child], con[child + 1])) ++child;}else{break;}}
}

向下调整算法也是堆的核心算法之一,其原理是将指定元素通过与其最大的(大堆,小堆相反)子结点比较,若不符合当前堆的排列规则(大堆小堆)就交换,符合就停止,不断地循环这个过程直到不能向下为止,从而将指定元素排到合适的位置。具体的实现过程就是先指定结点,将指定的结点视为父节点,算出父结点的子节点中最大的一个,将两者进行比较,比较逻辑由仿函数给出。若仿函数返回true就交换,之后将换完的子节点视为父节点,再次计算子节点不断循环;若仿函数返回false就说明到合适的位置了,停止循环即可。过程中要时刻注意越界问题。

迭代器构造

		template<class Iterator>priority_queue(Iterator begin, Iterator end){Iterator cur = begin;while (cur != end) con.push_back(*(cur++));int pos = size() / 2 - 1;while (pos >= 0) adjustdown(pos--);}

迭代其构造的思路有两种,一种是先全部拷进堆中,再排序,第二种是一个个push进去。效率差不多,我使用的第一种,因为难写一点,使用第一种写法需要注意使用向下调整算法比向上调整更优秀。为什么呢?使用向上调整算法就要从最上方也就是根节点开始把推遍历一遍才行,而使用向下调整算法则反之,要从堆的最下面的最后一个元素开始遍历对一遍。其中向上和向下的算法中单趟的时间复杂度都是logN,这样看来两者都是一样的,但是注意,两者都是有优化的空间的。当使用向上调整算法时,根节点因为没有父结点所以没有比的必要,可以优化掉一个;而使用向下调整算法时最下面一排的元素(满二叉树就是最下面一排,不是满二叉树就是最下面一排加最下面第二排部分,反正就是没有子节点的结点也就是叶子节点)因为没有子节点所以也没有比的必要,可以优化掉整整一排,要知道最后一排的结点数占了二叉树差不多一半,优化巨大,所以要用向下调整算法从最后一个有子结点的结点开始遍历,找这个结点的方式也很简单,最后一个有子结点的结点就是最后一个元素的父结点。

push

void push(const T& val)
{con.push_back(val);adjustup(con.size() - 1);
}

先入到容器的结尾,再用向上调整算法跳到合适的位置就行。

pop

void pop()
{std::swap(con.front(), con.back());con.pop_back();adjustdown(0);
}

由于我们这的堆是依靠容器中的位置模拟的二叉树,所以对于相对位置有着强逻辑,堆顶的元素不能直接头删,我们先将堆顶元素与最后一个元素交换,之后尾删,相当于删除堆顶在找了个替位的,之后对堆顶这个替位的使用向下调整算法调到合适的位置就行了。

由于priority_queue本质是一个容器适配器,其他的函数就只是对适配器接口的一些封装了,很简单,这里不过多赘述。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

测试——用例篇

目录 1. 测试用例 1.1 概念 2. 设计测试用例的万能公式 2.1 常规思考逆向思维发散性思维 2.2 万能公式 3. 设计测试用例例的方法 3.1 基于需求的设计方法 ​编辑 3.2 具体的设计方法 3.2.1 等价类 3.2.2 边界值 3.2.3 正交法 3.2.4 判定表法 3.2.5 场景法 3.2.6…

销售总监求职简历模板

模板信息 简历范文名称&#xff1a;销售总监求职简历模板&#xff0c;所属行业&#xff1a;其他 | 职位&#xff0c;模板编号&#xff1a;KREUNY 专业的个人简历模板&#xff0c;逻辑清晰&#xff0c;排版简洁美观&#xff0c;让你的个人简历显得更专业&#xff0c;找到好工作…

AE脚本 关键帧缓入缓出曲线调节工具 Flow v1.5.0 Win/Mac

Flow是一个非常好用的After Effects脚本,它可以让你更加轻松自如地调整关键帧的速度曲线,无需触碰老旧复杂的图形编辑器。 AE脚本介绍 Flow为After Effects带来了一个简洁的界面,使自定义动画曲线变得十分容易,无需深入研究速度和影响力这些让人困惑的概念 - 只需绘制一个曲线…

ACGRIME:用于全局优化和特征选择的自适应混沌高斯RIME优化器,附完整版免费代码

自然现象中&#xff0c;软冰的形成过程由 Set al. [42] 提出&#xff0c;软冰是空气中的过冷水滴在接触固体物体并冻结时形成的。这种现象发生在特定的气候条件下&#xff0c;当水蒸气尚未凝结时&#xff0c;导致冰覆盖的表面呈现出独特的树枝状和叶子状景观。它在软冰的生长和…

大模型开发学习笔记

文章目录 大模型基础大模型的使用大模型训练的阶段大模型的特点及分类大模型的工作流程分词化(tokenization)与词表映射 大模型的应用 进阶agent的组成和概念planning规划子任务分解ReAct框架 memory记忆Tools工具\工具集的使用langchain认知框架ReAct框架plan-and-Execute计划…

4.27-5.4学习周报

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 摘要Abstract一、方法介绍2.Rainbow Memory(RM)2.1多样性感知内存更新2.2通过数据增强增强样本多样性(DA) 二、使用步骤1.实验概况2.RM核心代码 总结 摘要 本博客概…

AI Rack架构高速互连的挑战:损耗设计与信号完整性的设计框架

在AI驱动的时代&#xff0c;系统设计已经从单一PCB的视角&#xff0c;逐步转向以整个rack为单位来考量。 对于信号完整性而言&#xff0c;焦点以不再局限于单一PCB上的损耗&#xff0c;而是扩展到芯片与芯片之间的端到端互连损耗&#xff08;end-to-end interconnect loss&…

杭电oj(1180、1181)题解

目录 1180 题目 思路 问题概述 代码思路分析 1. 数据结构与全局变量 2. BFS 函数 bfs 3. 主函数 main 总结 代码 1181 题目 思路 1. 全局变量的定义 2. 深度优先搜索函数 dfs 3. 主函数 main 总结 代码 1180 题目 思路 注&#xff1a;当走的方向和楼梯方向一…

软件测试概念

这里写目录标题 需求开发模型软件生命周期瀑布模型螺旋模型增量模型、迭代模型敏捷模型Scrum 测试模型V模型W模型&#xff08;双V模型&#xff09; 需求 用户需求&#xff1a;没有经过合理的评估&#xff0c;通常就是一句话 软件需求&#xff1a;是开发人员和测试人员执行工作…

数字基带信号和频带信号的区别解析

数字基带信号和数字频带信号是通信系统中两种不同的信号形式&#xff0c;它们的核心区别在于是否经过调制以及适用的传输场景。以下是两者的主要区别和分析&#xff1a; 1. 定义与核心区别 数字基带信号&#xff08;Digital Baseband Signal&#xff09; 未经调制的原始数字信号…

Linux52 运行百度网盘 解决故障无法访问repo nosandbox 未解决:疑似libstdc++版本低导致无法运行baidu网盘

昨日参考 哦 我是root Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64 没了 计划去手动下一个 还是不行 放弃 猜测是 centos7 过期了 一些依赖组件也没地方下载了 通过阿里云镜像站下载 之前安装的好像不是这个版本 还是计划用yum去下载依赖&#xff0c;先处…

2000-2022年上市公司数字经济专利申请数据

2000-2022年上市公司数字经济专利申请数据 1、时间&#xff1a;2000-2022年 2、来源&#xff1a;国家知识产权局 3、指标&#xff1a;年份、股票代码、股票简称、行业名称、行业代码、省份、城市、区县、行政区划代码、城市代码、区县代码、首次上市年份、上市状态、数字经济…

机器学习之五:基于解释的学习

正如人们有各种各样的学习方法一样&#xff0c;机器学习也有多种学习方法。若按学习时所用的方法进行分类&#xff0c;则机器学习可分为机械式学习、指导式学习、示例学习、类比学习、解释学习等。这是温斯顿在1977年提出的一种分类方法。 有关机器学习的基本概念&#xff0c;…

Chromium 134 编译指南 - Android 篇:安装构建依赖项(七)

1. 引言 欢迎来到《Chromium 134 编译指南》系列的第七篇文章&#xff01;在前面的章节中&#xff0c;我们已经成功获取了Chromium源代码&#xff0c;并将其配置为支持Android平台。这些步骤为我们的编译之旅奠定了坚实的基础&#xff0c;但在开始实际编译之前&#xff0c;我们…

java 进阶 1.0

静态方法 static 就是能直接用&#xff0c;不用再new一个对象了 一般java中Math等静态类就是可以直接使用其方法 main函数里面不能包含太多的逻辑性语句&#xff0c;全部写成模块 写好程序之后如何测试呢&#xff1f; 使用junit&#xff0c;不能在main函数里测试 测试本身就…

中小企业MES系统详细设计

版本&#xff1a;V1.1 日期&#xff1a;2025年5月2日 一、设备协议兼容性设计 1.1 设备接入框架 #mermaid-svg-PkwqEMRIIlIBPP58 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-PkwqEMRIIlIBPP58 .error-icon{fill…

Spring Security会话管理

用户认证通过后&#xff0c;为了避免用户的每次操作都进行认证&#xff0c;可以将用户的信息保存在会话中。会话就是系统为了保持当前用户的登录状态所提供的机制&#xff0c;常见的有基于Session方式、基于Token方式等。Spring Security提供会话管理功能&#xff0c;只需要配置…

PostgreSQL数据库操作基本命令

常用操作sql &#x1f510; 用户管理 -- 创建用户 CREATE USER username WITH PASSWORD password;-- 修改用户密码 ALTER USER username WITH PASSWORD newpassword;-- 删除用户 DROP USER username;&#x1f4e6; 数据库操作 -- 创建数据库 CREATE DATABASE dbname;-- 删除…

[吾爱出品] 网文提取精灵_4.0

网文提取精灵 链接&#xff1a;https://pan.xunlei.com/s/VOPDvKljcT3EWLjpt5LeDZvfA1?pwdw8kq# 易语言写的&#xff0c;介意的不要下载 相对网文提取工具_2.10.02版&#xff0c;因为是重写界面&#xff0c;目前版本限制最高5线程&#xff0c;暂时不支持批处理。 虽然不支…

每日算法-250502

每日算法 - 2025.05.02 记录一下今天刷的几道 LeetCode 算法题。 3191. 使二进制数组全部等于 1 的最少操作次数 I 题目 思路 贪心 解题过程 遍历数组 nums。当我们遇到 nums[i] 时&#xff1a; 如果 nums[i] 是 1&#xff0c;我们不需要进行操作&#xff0c;因为目标是全 …