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

news2024/11/25 18:32:12

文章目录

  • 一.双端队列——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.coloradmin.cn/o/785132.html

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

相关文章

疲劳驾驶检测和识别2:Pytorch实现疲劳驾驶检测和识别(含疲劳驾驶数据集和训练代码)

疲劳驾驶检测和识别2&#xff1a;Pytorch实现疲劳驾驶检测和识别(含疲劳驾驶数据集和训练代码) 目录 疲劳驾驶检测和识别2&#xff1a;Pytorch实现疲劳驾驶检测和识别(含疲劳驾驶数据集和训练代码) 1.疲劳驾驶检测和识别方法 2.疲劳驾驶数据集 &#xff08;1&#xff09;疲…

whistle代理

安装whistle npm install whistle -g --registryhttps://registry.npm.taobao.org启动w2代理 w2 startchrome浏览器安装插件whistle&#xff0c;并启用代理状态 web端代理到本地 浏览器访问http://127.0.0.1:8899/ 配置代理url [参考] https://blog.csdn.net/u010106375/ar…

C语言:程序环境和预处理

编译一个C程序设计很多步骤,大致为预处理,编译,汇编和链接. 在讲解预处理阶段之前,先简单总述一下程序的编译和链接. 1. 程序的编译和链接 链接是将各种代码和数据片段收集并组合成为一个单一文件的过程,这个文件可被加载(复制)到内存并执行. 这里有两个源文件构成了一个程序…

计算机内存中的缓存Cache Memories

这篇写一下计算机系统中的缓存Cache应用场景和实现方式介绍。 Memory hierarchy 在讲缓存之前&#xff0c;首先要了解计算机中的内存结构层次Memory hierarchy。也就是下图金字塔形状的结构。 从上到下&#xff0c;内存层次结构如下&#xff1a; 寄存器&#xff1a;这是计算机…

自动化测试与手工测试比较

既然现在有了自动化测试&#xff0c;甚至现在许多团队在使用人工智能的方法&#xff0c;逐渐让机器来取代人的测试。那么作为测试工程师的人未来会不会消失?这是一个摆在许多人面前的一个严肃的问题。去年刚刚过世的著名的天体物理学家斯蒂芬威廉霍金(Stephen William Hawking…

Qt - macOS 安装配置

文章目录 一、关于 QT1.2 Qt的发展史1.3支持的平台1.4 Qt版本1.5 Qt 的优点1.6 成功案例 二、软件安装1、保证已 Xcode 和 Command Line Tools2、下载 QT3、下载 [qtcreator](http://download.qt.io/official_releases/qtcreator/)查看qt版本 三、创建工程Qt 常见用法 四、基础…

智能安全配电装置应用场景有哪些?

安科瑞 华楠 一、应用背景 电力作为一种清洁能源&#xff0c;给人们带来了舒适、便捷的电气化生活。与此同时&#xff0c;由于使用不当&#xff0c;维护不及时等原因引发的漏电触电和电气火灾事故&#xff0c;也给人们的生命和财产带来了巨大的威胁和损失。 为了防止低压配电…

音频转换工具怎么使用你了解吗?让我来跟你分享背后原理

相信小伙伴们平时都会听听喜欢的音乐放松心情吧&#xff0c;不过你是否遇到过&#xff0c;想在一个播放设备上放一首歌的时候&#xff0c;却发现不支持该格式&#xff1f;音频转换格式软件在我们的生活中扮演着越来越重要的角色。这些软件可以帮助我们将音频文件转换成不同的格…

炒股最好用的5个指标?_通达信公式

摘要: 炒股市场是一个充满挑战的领域&#xff0c;而找到可靠的指标来辅助投资决策是成功的关键之一。在众多的指标中&#xff0c;神奇指标网提供了五个被广泛认为是炒股最好用的指标。本文将详细介绍这五个指标&#xff0c;包括其原理和如何应用它们来辅助投资决策。 导言: …

蓝桥杯专题-真题版含答案-【图形排版】【包子凑数】【位反序数】【自守数】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

Java进阶 —— 多进程并发

前言 在系统学完Java的面向对象编程之后&#xff0c;我们需要认真地来学习Java并发编程&#xff0c;我们在学习计算机操作系统的时候也都了解过进程、线程和协程的概念。在这篇文章中荔枝主要会梳理有关线程创建、线程生命周期、同步锁和死锁、线程通信和线程池的知识&#xff…

android app控制ros机器人一

android开发app&#xff0c;进而通过控制ros机器人&#xff0c;记录开发过程 查阅资料&#xff1a; rosjava使用较多&#xff0c;已经开发好的app也有开源的案例 rosjava GitHub https://github.com/ros-autom/RobotCA https://github.com/ROS-Mobile/ROS-Mobile-Android…

因果推断(一)合成控制法(SCM)

因果推断&#xff08;一&#xff09;合成控制法&#xff08;SCM&#xff09; 在互联网时代&#xff0c;产品迭代速度越来越快&#xff0c;营销活动也越来越多。分析师因此需要快速的量化每次迭代或每次营销的效果&#xff0c;探索改变与结果之间的因果关系&#xff0c;并将优秀…

idea如何解决导入的项目不是Maven工程(文件下面没有蓝色的方格)二

简介&#xff1a; Maven项目导入&#xff0c;idea不识别项目 解决方法&#xff1a; 选中pom.xml -- 右键 -- Add as Maven Project

使用Python搭建代理服务器- 爬虫代理服务器详细指南

搭建一个Python爬虫代理服务器可以让你更方便地管理和使用代理IP。下面是一个详细的教程来帮助你搭建一个简单的Python爬虫代理服务器&#xff1a; 1. 首先&#xff0c;确保你已经安装了Python。你可以在官方网站(https://www.python.org/)下载并安装最新版本的Python。 2. 安…

Spring 中简单存取 Bean 的相关注解

目录 前言存储 Bean 对象五大类注解方法注解&#xff08;Bean&#xff09; 获取 Bean 对象 (Autowired)属性注入多个同类型 Bean 注入怎么办&#xff1f; Setter 注入构造方法注入&#xff08;官方推荐&#xff09; 前言 之前我们存储获取 Bean 的操作很繁琐&#xff0c;需要将…

在职硕士|2023级中国社科院-美国杜兰大学合办双证能源管理硕士(MME)

金融硕士 在职硕士|2023级中国社科院-美国杜兰大学合办双证能源管理硕士&#xff08;MME&#xff09; 中国社会科学院大学与美国杜兰大学合作举办的能源管理专业硕士学位教育项目&#xff08;UCASS-Tulane Master of Management in Energy&#xff0c;简称MME&#xff09;于2…

《人工智能安全》课程总体结构

1 课程内容 人工智能安全观&#xff1a;人工智能安全问题、安全属性、技术体系等基本问题进行了归纳整理。人工智能安全的主要数据处理方法&#xff0c;即非平衡数据分类、噪声数据处理和小样本学习。人工智能技术赋能网络空间安全攻击与防御&#xff1a;三个典型实例及攻击图…

mybatis_配置之属性优化

概念 别名优化&#xff1a; 类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置&#xff0c;意在降低冗余的全限定类名书写。例如&#xff1a; 在xml文件里为SQL映射文件中定义返回值类型的属性起个别名 之后直接使用User进行使用 核心配置文件&#xff1a; MyBa…

常见面试题分享1

一、对JVM的了解 1.1 什么是JVM&#xff1f; JVM&#xff08;Java Virtual Machine&#xff09;&#xff0c;俗称Java虚拟机。它是一个虚构出来的计算机&#xff0c;是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java语言的一个非常重要的特点就是与平台的无关性。…