C++: 优先级队列的模拟实现和deque
目录
一、优先级队列
1.1优先级队列 priority_queue介绍
1.2优先级队列的使用
1.3priority_queue的模拟实现
二、deque
2.1deque介绍
2.2deque的优缺点
2.3为什么选择deque作为stack和queue的底层默认容器
一、优先级队列
1.1优先级队列 priority_queue介绍
1.11 优先级队列是一种容器适配器,根据严格的弱排序,它的第一个元素总是它所有元素中最大 的。
适配器:是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),这种设计模式将一个类的接口转换成客户希望的另一个接口。比方说,在stack里面,把push接口转换成调用另一个容器的push_back,这个容器的类放在私有里,是根据初始化来定的,你希望这个底层容器是vector,那么在调用stack的push时,实际调用的就是vector的push_back进行插入元素操作。stack只是一个壳子,vector才是存储数据的底层,只是取数据和其他操作,得按照stack的特点进行。
容器适配器:虽然stack和queue也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称之为容器适配器,因为stack和queue只是对其他容器进行了包装,STL中stack和queue默认底层容器使用deque。
deque后文介绍。
1.12 此上下文环境类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)
1.13 优先队列被实现为容器适配器,容器适配器就是将特定容器封装作为它的底层容器,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称之为优先队列的顶部。
1.14 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。底层容器应该可以通过随机访问迭代器访问,并支持以下操作:
empty(): 检测容器是否为空
size(): 返回容器的元素个数
front(): 返回容器的第一个元素
push_back(): 尾插一个元素进容器
pop_back(): 尾删一个元素
1.15 标准容器类vector和deque满足这些要求,如果没有指定特定容器类实例化priority_queue,一般使用vector作为其底层容器。
1.16 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作。
1.2优先级队列的使用
优先级队列默认使用vector作为其底层存储结构的容器,在vector上又加了堆算法,令vector成为堆结构。因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。注意:默认情况下priority_queue是大堆。
priority_queue常用的函数和接口说明
函数接口 | 接口说明 |
priority_queue()/priority_queue(first,last) | 构造函数,第一个是构造一个空的优先级队列,第二个是用迭代器指向的区间进行构造 |
empty() | 队列是否是空 |
push(x) | 在优先级队列中插入一个元素x |
pop() | 删除优先级队列中的堆顶元素 |
top() | 返回优先级队列中的堆顶元素 |
1.3priority_queue的模拟实现
为了防止前面数据结构的建堆都忘了,代码我会注释一下的。
#pragma once
#include <iostream>
using namespace std;
#include <assert.h>
#include <vector>
#include <list>namespace ting
{//创建一个仿函数,为元素的大小比较提供template<class T>struct less{//()操作符重载,这样less实例化的对象(如compare)在调用该函数时,就直接compare(),//括号里填参数就好。通过()操作符重载,把一个类对象当作函数来使用,非常方便。bool operator()(const T& p1, const T& p2){return p1 < p2;}};template<class T, class container = vector<int>,class Compare = less<T>>class priority_queue{Compare _compare;public:priority_queue(const Compare& comFunc = Compare())//Compare是一个类,后面
//没写类名意思是匿名对象,然后用comFunc给了它名字。
//得到名字的comFunc传给_comFunc,如果是less就less,Greater就 //Greater,不传就默认用Compare(),默认是比小 :_compare(comFunc){}template<class InputIterator>priority_queue(InputIterator first, InputIterator last, const Compare& comFunc = Compare()):_compare(comFunc){while (first != last){_cn.push_back(*first);++first;}//向下调整建大堆for (int i = (_cn.size() - 1 - 1) / 2; i >= 0; --i){AdjustDown(i);//从最后一颗树的父亲节点开始调,每次调一颗树}}void AdjustDown(size_t parent)//向下调整,从父亲节点开始调{size_t child = 2 * parent + 1;//孩子节点是父亲节点的2倍+1,设定为左孩子while (child < _cn.size())//比到最后一个孩子节点{//如果右孩子比左孩子大,左孩子就被右孩子取代。if (child + 1 < _cn.size() - 1 && _compare(_cn[child],_cn[child+ 1])){++child;}//父亲节点的值和两个孩子中更大的值比较,父亲节点小就交换位置,继续往下比if (child < _cn.size() && _compare(_cn[parent], _cn[child])){swap(_cn[parent], _cn[child]);parent = child;child = 2 * parent + 1;}else//如果父亲没有比孩子节点再小了,那后面的已经是一个堆了,不用再调整{break;}}}void AdjustUp(size_t child)//向上调整,从最后一个孩子节点开始调,所以是对尾插的元素进//行调整{size_t parent = (child - 1) / 2;while (child > 0){if (_compare(_cn[parent], _cn[child]))//如果父亲节点小于孩子,交换位置{swap(_cn[parent], _cn[child]);parent = child;child = 2 * parent + 1;}else//如果父亲节点不小于,那放在这不用管了。{break;}}}bool empty(){return _cn.empty();}size_t size(){return _cn.size();}void push(const T& x)//尾插时,这里已经是一个堆了,所以前面的不用调,从最后一个开始{_cn.push_back(x);AdjustUp(_cn.size()-1);//最后一个节点是孩子节点,适用于向上调整}void pop(){assert(!empty());swap(_cn[0], _cn[_cn.size() - 1]);_cn.pop_back();//删除头节点以后,最后面的节点到第一个,就要从第一个开始调AdjustDown(0);//所以是向下调整}const T& Top(){return _cn[0];}private:container _cn;};void test1(){int a[] = { 1, 4, 2, 7, 8, 9 };priority_queue<int> pq(a, a + 6);while (!pq.empty()){cout << pq.Top() << " ";pq.pop();}}
}
二、deque
2.1deque介绍
deque(双端队列):是一种双开口的“连续”空间的数据结构,双开口的含义是:可以再头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素,和list比较,空间利用率比较高。
deque并不是真正连续的空间,而是由一小段连续的小空间拼接而成,实际deque类似于一个动态的二维数组。
它先开辟一块指针数组,每一个指针都指向一块大小相等的空间(比如40个字节),平常插入删除元素就在指针指向的空间里操作,而且一般是从中间的空间开始用。这样当这块指针空间也被填满时,就重新动态开辟一块连续的空间。
双端队列底层是一块假象的连续空间,实际上是分段连续的,指针指向的空间是连续的。但指针指向某一块连续空间,和前一个指针指向的连续空间之间未必是连续的。后一个指针指向的连续空间是从堆区开辟的。要用的时候才开辟,这怎么连续?
2.2deque的优缺点
与vector比较,deque的优势是:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不需要搬移大量的元素,因此其效率是比vector高的。
与list比较:其底层是连续空间,空间利用率比较高,不需要存储额外字段。
但是deque有一个致命缺陷:不适合遍历,因为在遍历时,迭代器要频繁去检测是否移到某段小空间的边界,导致效率低下。而序列式场景中,经常需要遍历,大多数情况下优先考虑vector和list。deque的应用并不多,而且目前看到的应用就是作为STL中stack和queue的底层默认容器。
2.3为什么选择deque作为stack和queue的底层默认容器
1.stack和queue不需要遍历,因此stack和queue也没有迭代器,它们只需要在固定的一段进行操作就好。
2.在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据);deque中的元素增长时,deque不仅效率高,而且内存使用率高。
这结合了deque的优点,而且完美避开了其缺点。
相关文章:

C++: 优先级队列的模拟实现和deque
目录 一、优先级队列 1.1优先级队列 priority_queue介绍 1.2优先级队列的使用 1.3priority_queue的模拟实现 二、deque 2.1deque介绍 2.2deque的优缺点 2.3为什么选择deque作为stack和queue的底层默认容器 一、优先级队列 1.1优先级队列 priority_queue介绍 1.11 优先级队…...

C++ socket epoll IO多路复用
IO多路复用通常用于处理单进程高并发,在Linux中,一切皆文件,一个socket连接会对应一个文件描述符,在监听多个文件描述符的状态应用中epoll相对于select和poll效率更高 epoll本质是系统在内核维护了一颗红黑树,监听的文…...

缓存IO与直接IO
IO类型 缓存 I/O 缓存 I/O 又被称作标准 I/O,大多数文件系统的默认 I/O 操作都是缓存 I/O。在 Linux 的缓存 I/O 机制中,数据先从磁盘复制到内核空间的缓冲区,然后从内核空间缓冲区复制到应用程序的地址空间(用户空间࿰…...

输入输出(3)——C++的标准输入流
目录 一、cin 流 二、成员函数 get 获取一个字符 (一)无参数的get函数。 (二)有一个参数的get函数。 (三)有3个参数的get函数 (四)用成员函数 getline 函数读取一行字符 (五)用成员函数 read 读取一串字符 (六)istream 类…...

[力扣题解] 344. 反转字符串
题目:344. 反转字符串 思路 双指针法 代码 class Solution { public:void reverseString(vector<char>& s) {int i, j, temp;for(i 0, j s.size()-1; i < j; i, j--){temp s[j];s[j] s[i];s[i] temp;}} };...

找不到msvcr110.dll无法继续执行代码的原因分析及解决方法
在计算机使用过程中,我们经常会遇到一些错误提示,其中之一就是找不到msvcr110.dll文件。这个错误通常发生在运行某些程序或游戏时,系统无法找到所需的动态链接库文件。为了解决这个问题,下面我将介绍5种常见的解决方法。 一&#…...

深入理解数仓开发(一)数据技术篇之日志采集
前言 今天开始重新回顾电商数仓项目,结合《阿里巴巴大数据之路》和尚硅谷的《剑指大数据——企业级电商数据仓库项目实战 精华版》来进行第二次深入理解学习。之前第一次学习数仓,虽然尽量放慢速度力求深入理解,但是不可能一遍掌握࿰…...

Edge浏览器:重新定义现代网页浏览
引言 - Edge的起源与重生 Edge浏览器,作为Microsoft Windows标志性的互联网窗口,源起于1995年的Internet Explorer。在网络发展的浪潮中,IE曾是无可争议的霸主,但随着技术革新与用户需求的演变,它面临的竞争日益激烈。…...

HDFS,HBase,MySQL,Elasticsearch ,MongoDB分别适合存储什么特征的数据?
HDFS(Hadoop Distributed File System)通常用于存储大规模数据,适合存储结构化和非结构化数据,例如文本文件、日志数据、图像和视频等。 HBase是基于Hadoop的分布式数据库,适合存储大量非结构化和半结构化的数据&…...

ArcGIS中离线发布路径分析服务,并实现小车根据路径进行运动
ArcGIS中离线发布路径分析服务,您可以按照以下步骤操作: 准备ArcMap项目: 打开ArcMap并加载包含网络分析图层的项目。在ArcMap中,使用 Network Analyst Toolbar 或 Catalog 创建网络数据集(Network Dataset)…...

时政|医疗结果互认
背景(存在的问题) 看同一种病,换一家医院甚至换一个院区、换一个科室,检查检验还得再来一遍,费钱又费时。开展检查检验结果互认,可以明显减轻患者就医负担。患者不用做重复检查,也可节约就医时…...

华为OD机试【找出通过车辆最多颜色】(java)(100分)
1、题目描述 在一个狭小的路口,每秒只能通过一辆车,假设车辆的颜色只有 3 种,找出 N 秒内经过的最多颜色的车辆数量。 三种颜色编号为0 ,1 ,2。 2、输入描述 第一行输入的是通过的车辆颜色信息[0,1,1,2] ࿰…...

hyperf 多对多关联模型
这里使用到三张表,一张是用户(users),一张是角色(roles),一张是用户角色关联表(users_roles), 首先创建用户模型、角色模型 php bin/hyperf.php gen:model users php bin/hyperf.php gen:model rolesusers…...

每日力扣刷题day03(从零开始版)
文章目录 2024.5.24(5题)2828.判别首字母缩略词题解一题解二 1365.有多少小于当前数字的数字题解一题解二题解三 2469.温度转换题解一题解二 1502.判断能否形成等差数列题解一题解二 2351.第一个出现两次的字母题解一题解二 2024.5.24(5题&am…...

误差反向传播简介与实现
误差反向传播 导语计算图反向传播链式法则 反向传播结构加法节点乘法节点 实现简单层加法乘法 激活函数层实现ReLUSigmoid Affine/Softmax层实现Affine基础版批版本 Softmax-with-Loss 误差反向传播实现梯度确认总结参考文献 导语 书上在前一章介绍了随机梯度下降法进行参数与…...

ATmega328P加硬件看门狗MAX824L看门狗
void Reversewdt(){ //硬件喂狗,11PIN接MAX824L芯片WDIif (digitalRead(11) HIGH) {digitalWrite(11, LOW); //低电平} else {digitalWrite(11, HIGH); //高电平 }loop增加喂狗调用 void loop() { …… Reversewdt();//喂狗 }...

【Redis】 String类型的内部编码与使用环境
文章目录 🍃前言🌴内部编码🎄典型使用场景🚩缓存功能🚩计数(Counter)功能🚩共享会话(Session)🚩验证码功能 ⭕总结 🍃前言 本篇文章重…...

HarmonyOS interface router scale pageTransition SlideEffect.Left ArkTS ArkUI
🎬️create Component export default struct TitleBar {build(){Row(){Text(transition).fontSize(30fp).fontColor(Color.White)}.width(100%).height(8%).backgroundColor(#4169E1).padding({left:10})}}🎞️interface export interface IList{ti…...

Go语言(Golang)的开发框架
在Go语言(Golang)的开发中,有多种开发框架可供选择,它们各自具有不同的特点和优势。以下是一些流行的Go语言开发框架,选择Go语言的开发框架时,需要考虑项目需求、团队熟悉度、社区支持、框架性能和可维护性…...

Python入门第三课——Python 数据类型(详细)
文章回顾 Python入门第一课——Python起步安装、Sublime Text安装教程,环境配置Python入门第二课——Python的变量和简单数据类型 目录 文章回顾前言一、Python的详细数据类型二、各种数据类型和使用方法1.Number(数字)2、String(…...

html入门
<!DOCTYPE html><!--每个文件都要加上这个,是html文件的主题--> <html><!--查不多就是c预言的main函数,从头括到尾部--><head><meta http-equiv"Content-Type" content"text/html;charsetutf-8" /…...

蓝桥杯杨辉三角
PREV-282 杨辉三角形【第十二届】【蓝桥杯省赛】【B组】 (二分查找 递推): 解析: 1.杨辉三角具有对称性: 2.杨辉三角具有一定规律 通过观察发现,第一次出现的地方一定在左部靠右的位置,所以从…...

【活动】开源与闭源大模型:探索未来趋势的双轨道路
🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 💫个人格言: "如无必要,勿增实体" 文章目录 开源与闭源大模型:探索未来趋势的双轨道路引言一、开源大模型&#…...

虚拟局域网(VLAN)
关键词:veth、vlan、bridge、iptables、nat、tcpdump、icmp、cidr、arp、路由表、计算机网络协议栈 前言 在过去的几十年里,互联网发展得非常快。许多新兴技术迅速崛起,也有不少曾经的主流技术被淘汰。然而,有些技术因为其基础性…...

内网穿透--Frp-简易型(速成)-上线
免责声明:本文仅做技术交流与学习... 目录 frp项目介绍: 一图通解: 编辑 1-下载frp 2-服务端(server)开启frp口 3-kali客户端(client)连接frp服务器 4-kali生成马子 5-kali监听 6-马子执行-->成功上线 frp项目介绍: GitHub - fatedier/frp: A fast reverse proxy…...

Python库之Scrapy的简介、安装、使用方法详细攻略
Python库之Scrapy的简介、安装、使用方法详细攻略 简介 Scrapy是一个快速的、高层次的web抓取和web抓取框架,用于抓取网站数据并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、信息处理或存储历史数据,以及各种其他用途。 …...

k8s配置pods滚动发布
背景 采用微服务架构部署的应用,部署方式都要用到容器化部署k8s容器编排,最近我在公司负载的系统也是用的上述架构部署,但是随着系统的运行,用户提的需求就会越多,每次更新的话都要停机发布,最用户侧来说就…...

C++vector的简单模拟实现
文章目录 目录 文章目录 前言 一、vector使用时的注意事项 1.typedef的类型 2.vector不是string 3.vector 4.算法sort 二、vector的实现 1.通过源码进行猜测vector的结构 2.初步vector的构建 2.1 成员变量 2.2成员函数 2.2.1尾插和扩容 2.2.2operator[] 2.2.3 迭代器 2…...

AWTK实现汽车仪表Cluster/DashBoard嵌入式GUI开发(七):快启
前言: 汽车仪表是人们了解汽车状况的窗口,而仪表中的大部分信息都是以指示灯形式显示给驾驶者。仪表指示灯图案都较为抽象,对驾驶不熟悉的人在理解仪表指示灯含义方面存在不同程度的困难,尤其对于驾驶新手,如果对指示灯的含义不求甚解,有可能影响驾驶的安全性。即使是对…...

基于springboot+vue的招聘信息管理系统
开发语言:Java框架:springbootJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:…...