双端队列(deque)与优先队列(priority_queue)

文章目录

  • 一.双端队列——deque
    • 1.deque的优点与缺点
    • 2.deque的原理
  • 二.优先队列——priority_queue
    • 1.什么是优先队列?
    • 2.优先队列的基本使用
    • 3.什么是仿函数?
    • 4.优先队列的模拟实现

一.双端队列——deque

在上一章stack、queue的模拟实现中,我们使用的是vector 来作为底层容器。但是,在标准库中,都是使用deque来作为底层容器的,那么deque究竟为何能受到青睐呢?

1.deque的优点与缺点

deque对标的是vectorlist,我们可以认为dequevectorlist的结合并且取其精华去其糟粕。

vector的优缺点

  1. 尾插尾删效率高,头插头删效率低
  2. 支持随机访问
  3. 扩容代价高

list的优缺点

  1. 头删头插效率高
  2. 尾插尾删效率高
  3. 不支持随机访问
  4. 不需要扩容

deque的优点

  1. 头删头插效率高
  2. 尾插尾删效率高
  3. 支持随机访问
  4. 扩容代价低(相比vector
  • deque看起来挺不错的,完美的继承了vectorlist的优点。但是,既然deque这么优秀,为什么我们又好像没怎么学习过它呢?答案是,它也有它的缺点。

deque的缺点

  1. 中间插入或删除效率低
  2. 没有vectorlist的优点那么极致

deque的产生就像是什么呢?就例如,我继承了爱因斯坦的高智商,又继承了泰森的力量,但是继承的过程有一些损耗,所以我既没有爱因斯坦极致的智商,又没有泰森极致的力量,我只是个普通人。所以我们说,deque相当于vectorlist的结合产品。

deque看似很中庸,实际用处不大,但是,作为stackqueue的底层容器却又刚好合适,因为栈和队列的性质完美的避开了deque的缺点,只用到了deque的优点——栈和队列只对头部或者尾部进行操作。

2.deque的原理

对于deque,我们只需要大致认识它的底层结构即可。

deque(双端队列):是一种双开口的“连续”空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高。

在这里插入图片描述
deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组,其底层结构如下图所示:

在这里插入图片描述

双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,落在了deque的迭代器身上,因此deque迭代器设计就比较复杂,如下图所示:

在这里插入图片描述
deque是如何借助其迭代器维护其假想连续的结构呢?

在这里插入图片描述

对于deque我们只需做到了解就可以。

二.优先队列——priority_queue

1.什么是优先队列?

priority_queuestackqueue相同,都是一种容器适配器。默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆。

优先级队列允许你以任意顺序插入元素,并且每次弹出的元素是当前优先级最高(及最大或最小)的元素。在priority_queue中,元素的插入顺序不影响元素的优先级,而是根据其优先级属性进行排序。

2.优先队列的基本使用

  • 包含头文件 < queue >
#include <queue>
  • 定义一个priority_queue对象
priority_queue<int> pq;
  • 向队列中插入一个元素
pq.push(1);
pq.push(5);
pq.push(2);
  • 从队列中弹出一个元素(该元素为队列内优先级最高的元素)
pq.pop();
  • 返回队列中优先级最高的元素(及堆顶的元素)
cout << pq.top() << endl;
  • 返回队列中的元素数量
cout << pq.size() << endl;
  • 判断队列是否为空
//empty()
if (pq.empty())
{cout << "Queue is empty" << endl;
}
else
{cout << "Queue is not empty" << endl;
}

特别注意

优先级队列默认是建大堆,也就是元素的值越大,优先级越高。我们可以通过一个传递模板参数来控制优先级的判别。所以,优先级队列在设计的时候用到了3个模板参数,而我们上一章所学习的stackqueue则是2个模板参数,如图:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

	// 默认情况下,创建的是大堆,其底层按照小于号比较priority_queue<int> pq1;// 如果要创建小堆,将第三个模板参数换成greater比较方式// 记得包含greater算法的头文件——#include <functional>priority_queue<int, vector<int>, greater<int>> pq2;

第三个模板参数仅仅只有比较大小的作用,我们也可以自己实现这样一个模板类来传递。像图中Compare这样的类所创建的对象,我们通常称它为——仿函数。因为该类的对象可以像函数一样使用。

3.什么是仿函数?

仿函数(functor)是一种行为类似于函数的对象,它可以像函数一样被调用。在C++中,仿函数通常是一个类,它重载了函数调用运算符operator(),并且可以像函数一样使用。

仿函数可以被用来封装一些操作或算法,它们可以被传递给其他函数或算法作为参数,或者作为返回值返回给调用者。由于仿函数是一个对象,因此可以在调用它们的过程中保持状态信息,这使得它们可以非常灵活地实现不同的行为。

例如上述的优先级队列又或是库中的sort函数,sort()函数可以接受一个仿函数对象作为第三个参数,这个仿函数对象将被用来比较两个元素的大小关系,这样我们就可以灵活的运用sort函数排序数列为升序或者降序了。

关于仿函数,我们点到为止。

4.优先队列的模拟实现

关于堆的结构前面已经详细讲解过点我

#include <iostream>
#include <vector>
using namespace std;namespace dianxia
{// 小于template<class T>class less{public:bool operator()(const T& x, const T& y){return x < y;}};// 大于template<class T>class greater{public:bool operator()(const T& x, const T& y){return x > y;}};// priority_queue类template<class T, class Container = vector<T>,class Compare=less<T>>class priority_queue{// 比较的对象Compare com;// 向上调整void adjust_up(int child){size_t  parent = (child - 1) / 2;while (child > 0){if (com(_con[parent] ,_con[child])){swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}// 向下调整void adjust_down(int parent){int child = parent * 2 + 1;while (child < _con.size()){// 确保child是两个孩子中大/小的那一个if (child + 1 < _con.size() && com(_con[child], _con[child + 1])){++child;}if (com(_con[parent], _con[child])){swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}}public:void push(const T& data){_con.push_back(data);adjust_up(_con.size()-1);}void pop(){// 堆顶元素与堆尾元素互换swap(_con[0],_con[_con.size() - 1]);_con.pop_back();adjust_down(0);}const T& top(){return _con[0];}size_t size(){return _con.size();}bool empty(){return _con.empty();}private:Container _con;};
}

本文到此结束,码文不易,还请多多支持哦!!!

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

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

相关文章

C# LINQ和Lambda表达式对照

C# LINQ和Lambda表达式对照 1. 基本查询语句 Linq语法&#xff1a; var datafrom a in db.Areas select a ; Lamda语法&#xff1a; var datadb.Areas; sql语法&#xff1a; SELECT * FROM Areas2. 简单的WHERE语句 Linq语法&#xff1a; var datafrom a in db.orderI…

【Spring Boot Admin】客户端服务无法注册到监控平台的相关问题及解决方案

1、客户端服务整合了Spring Security 通过URL注册&#xff0c;需在客户端服务中添加如下配置 spring:# spring boot adminboot:admin:client:instance:metadata:user.name: ${spring.security.user.name}user.password: ${spring.security.user.password}通过注册中心注册&am…

Mysql 数据库开发及企业级应用

文章目录 1、Mysql 数据库开发及企业级应用1.1、为什么要使用数据库1.1.1、数据库概念&#xff08;Database&#xff09;1.1.2、为什么需要数据库 1.2、程序员为什么要学习数据库1.3、数据库的选择1.3.1、主流数据库简介1.3.2、使用 MySQL 的优势1.3.3、版本选择 1.4、Windows …

Redis 执行Lua脚本

Redis 执行lua 脚本 redis incr 命令当Key不存在时会默认设置key 并自增为1,如果需要在key不存在时重新初始化key 可以在应用程序中判断&#xff0c;也可以直接使用lua脚本 Redis 执行lua脚本命令 Script load 将脚本 script 添加到Redis服务器的脚本缓存中&#xff0c;并不…

介绍Tensorflow的基本概念和场景

TensorFlow是一种开源的机器学习框架&#xff0c;由Google开发&#xff0c;用于构建和训练人工神经网络。它使用图形表示来表示数学计算&#xff0c;其中节点表示操作&#xff0c;边表示数据流。以下是TensorFlow的基本概念&#xff1a; Tensor&#xff1a;TensorFlow的计算单位…

神经网络随记-参数矩阵、剪枝、模型压缩、大小匹配、、

神经网络的参数矩阵 在神经网络中&#xff0c;参数矩阵是模型学习的关键部分&#xff0c;它包含了神经网络的权重和偏置项。下面是神经网络中常见的参数矩阵&#xff1a; 权重矩阵&#xff08;Weight Matrix&#xff09;&#xff1a;权重矩阵用于线性变换操作&#xff0c;将输…

k8s+containerd安装

准备环境 准备两台服务器节点&#xff0c;如果需要安装虚拟机&#xff0c;可以参考《wmware和centos安装过程》 机器名IP角色CPU内存centos01192.168.109.130master4核2Gcentos02192.168.109.131node4核2G 设置主机名&#xff0c;所有节点都执行 vim /etc/hosts #增加 192.…

【VUE】解决图片视频加载缓慢/首屏加载白屏的问题

1 问题描述 在 Vue3 项目中&#xff0c;有时候会出现图片视频加载缓慢、首屏加载白屏的问题 2 原因分析 通常是由以下原因导致的&#xff1a; 图片或视频格式不当&#xff1a;如果图片或视频格式选择不当&#xff0c;比如选择了无损压缩格式&#xff0c;可能会导致文件大小过大…

unity 控制text根据字数自动扩展大小,并扩展UI背景

需求&#xff1a;文字内容位置保持不变&#xff0c;向下增加&#xff0c;背景框随之同步扩展。 1.UGUI 九宫格 拉伸 对背景框图片资源处理&#xff0c;避免图片拉伸。 (10条消息) unity UGUI 九宫格 拉伸_unity九宫格拉伸_野区捕龙为宠的博客-CSDN博客 2.背景框添加组件 3.…

【C#】set和get访问器的使用例子

假设我们有一个名为Person的类&#xff0c;该类具有一个私有字段_age表示人的年龄。我们可以使用get和set访问器来访问和修改该字段。 csharp public class Person { private int _age; public int Age { get > _age; // get访问器用于获取_age的值 set > _age value; /…

mysql 自增长键值增量设置

参考文章 MySQL中auto_increment的初值和增量值设置_auto_increment怎么设置_linda公馆的博客-CSDN博客 其中关键语句 show VARIABLES like %auto_increment% set auto_increment_increment4; set auto_increment_offset2;

php裁剪图片,并给图片加上水印

本次以裁剪四个图片为例&#xff0c;图片如下 代码如下 public function cutImg($imgUrl){try{// 读取原始图片$src_img imagecreatefromjpeg($imgUrl);// 获取原始图片的宽度和高度$src_width imagesx($src_img);$src_height imagesy($src_img);// 计算每个部分的宽度和高…

【数字信号处理】带通采样定理及其MATLAB仿真

目录 一、带通采样定理1.1 内容1.2 公式推导 二、MATLAB信号仿真2.1 信号仿真实验2.2 MATLAB代码 三、总结参考 一、带通采样定理 按照奈奎斯特采样定理(低通采样)&#xff0c;采样频率 f s f_{s} fs​ 要大于等于信号中最高频率 f m a x f_{max} fmax​ 的2倍&#xff0c;才…

C++OpenCV(2):图像处理基础概念与操作

&#x1f506; 文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 &#x1f506; OpenCV项目地址及源代码&#xff1a;点击这里 文章目录 图形读取与显示加载图片显示图片打印图片信息保存图片 色彩模型转换RGB颜色模型HSV颜色模型HLS模型LAB模型 图像像素读写操作像素算数运…

macOS 源码编译 qpress

╰─➤ git clone https://github.com/PierreLvx/qpress.git ╰─➤ cd qpress ╰─➤ make g -O3 -o qpress -x c quicklz.c -x c qpress.cpp aio.cpp utilities.cpp -lpthread -Wall -Wextra -Werror ╰─➤ sudo make install …

怎么快速定位bug?怎么编写测试用例?

目录 01定位问题的重要性 02问题定位技巧 03初次怎么写用例 作为一名测试人员如果连常见的系统问题都不知道如何分析&#xff0c;频繁将前端人员问题指派给后端人员&#xff0c;后端人员问题指派给前端人员&#xff0c;那么在团队里你在开发中的地位显而易见 &#xff0c;口碑…

垃圾回收标记阶段算法

1.标记阶段的目的 主要是在GC在前&#xff0c;判断出哪些是有用的对象&#xff0c;哪些是需要回收的对象&#xff0c;只有被标记为垃圾对象&#xff0c;GC才会对其进行垃圾回收。判断对象是否为垃圾对象的两种方式&#xff1a;引用计数算法和可达性分析算法。 2.引用计数算法…

[QT编程系列-33]:科学计算 - 开源数值计算库GNU Scientific Library(简称GSL)

目录 第1章 简介 1.1 概述 1.2 主要功能 1.3 C接口 1.4 在QT中使用GSL的步骤 第2章 GSL C函数库 2.1 功能概述 2.2 代码示例 第1章 简介 1.1 概述 GNU Scientific Library&#xff08;简称GSL&#xff09;是一个开源数值计算库&#xff0c;旨在提供各种数学和科学计算…

如何搭建使用dubbo-Admin?

dubbo-Admin介绍 一款用于dubbo可视化界面操作的管理平台 dubbo-Admin特点 dubbo-Admin是dubbo的管理界面平台&#xff0c;且是一个前后端分离的项目&#xff0c;前端使用vue&#xff0c;后端使用springboot。 软件下载 dubbo-admin-0.5.0.zip 软件使用

base-R(又称为基础R)中的apply函数族

说明&#xff1a;此为学习baseR中apply函数族笔记&#xff0c;仅学习使用。 C编程语言使用循环&#xff0c;但是R软件提倡使用向量化操作和apply系列函数来批量处理数据&#xff0c;从而大大简化了计算&#xff0c;提高代码的速度、可读性和可维护性。其实&#xff0c;大部分ap…