【C++】queue和priority_queue的用法及模拟实现

news2024/10/5 20:21:56

目录

  • 一、queue的简介及其使用
    • 1、queue的简介
    • 2、queue的使用
    • 2、queue的模拟实现
  • 二、priority_queue的简介及其使用
    • 1、priority_queue的简介
    • 2、priority_queue的使用
    • 3、priority_queue的模拟实现

一、queue的简介及其使用

1、queue的简介

  1. queue是一种容器适配器,专门用在先进先出操作的上下文中环境中,其中的元素只允许从容器一端插入,另一端提取。
  2. queue是作为容器适配器来实现的,容器适配器是对特定类封装作为其底层的容器,queue提供一组特定的成员函数来访问其元素,元素是从特定容器的队尾入队,从对头出队。
  3. 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作:
    1、empty:检测队列是否为空
    2、size:返回队列中有效元素的个数
    3、front:返回队头元素的引用
    4、back:返回队尾元素的引用
    5、push_back:在队列尾部入队列
    6、pop_front:在队列头部出队列
  4. 标准容器deque和list都符合这些需求,在默认情况下,stack指定特定的底层容器为deque。
    在这里插入图片描述

2、queue的使用

函数声明接口说明
queue()构造空的队列
empty()检测队列是否为空,是返回true,否则返回false
size()返回队列中有效元素的个数
front()返回队头元素的引用
back()返回队尾元素的引用
push()在队尾将元素val入队列
pop()将队头元素出队列
void TestQueue()
{
    queue<int, list<int>> q;
    int sum = 0;

    for (int i = 1; i <= 10; i++)
    {
        q.push(i);
    }
    cout << "个数: " << q.size() << endl;//结果:个数:10
    while (!q.empty())
    {
        sum += q.front();
        q.pop();
    }
    cout << "合计: " << sum << endl;//结果:合计:55
}

2、queue的模拟实现

namespace hxj
{
	template<class T, class Container = list<T>>
	//template<class T, class Container = deque<T>>
	class queue
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}

		void pop()
		{
			_con.pop_front();
		}

		const T& front()
		{
			return _con.front();
		}

		const T& back()
		{
			return _con.back();
		}

		size_t size()
		{
			return _con.size();
		}

		bool empty()
		{
			return _con.empty();
		}

	private:
		Container _con;
	};
}

注意:因为queue的接口中存在头删和尾插,因此使用vector来封装效率太低,故可以借助list或deque来模拟实现queue,

二、priority_queue的简介及其使用

1、priority_queue的简介

  1. 优先级队列是一种容器适配器,专门设计为根据一些严格的弱排序标准,它的第一个元素始终是它所包含的元素中最大的一个。
  2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先级队列中位于顶部的元素)。
  3. 优先级队列被实现为容器适配器,容器适配器是使用特定容器类的封装对象作为其底层容器的类,提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,即优先级队列的顶部。
  4. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问,并支持以下操作:
    1、empty():检测容器是否为空
    2、size():返回容器中有效元素个数
    3、front():返回容器中第一个元素的引用
    4、push_back():在容器尾部插入元素
    5、pop_back():删除容器尾部元素
  5. 标准容器类vector和deque满足这些要求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。
  6. 需要支持随机访问迭代器才能始终在内部保持堆结构。这是由容器适配器在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成的。

2、priority_queue的使用

优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。
注意:默认情况下priority_queue是大堆。

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

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

void TestPriorityQueue()
{
	// 默认情况下,创建的是大堆,其底层按照小于号比较
	vector<int> v{ 2,9,1,3,6,4,5,7,0,8 };
	priority_queue<int> q1;
	for (auto& e : v)
		q1.push(e);
	cout << q1.top() << endl;//结果:9

	// 如果要创建小堆,将第三个模板参数换成greater比较方式
	priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());
	cout << q2.top() << endl;//结果:0
}

其中greater的头文件:#include

注意: 如果在priority_queue中放自定义类型的数据,用户需要在自定义类型中提供> 或者< 的重载。

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}

	bool operator<(const Date& d)const
	{
		return (_year < d._year) ||
			(_year == d._year && _month < d._month) ||
			(_year == d._year && _month == d._month && _day < d._day);
	}

	bool operator>(const Date& d)const
	{
		return (_year > d._year) ||
			(_year == d._year && _month > d._month) ||
			(_year == d._year && _month == d._month && _day > d._day);
	}

	friend ostream& operator<<(ostream& _cout, const Date& d)
	{
		_cout << d._year << "-" << d._month << "-" << d._day;
		return _cout;
	}

private:
	int _year;
	int _month;
	int _day;
};

void TestPriorityQueue2()
{
	// 大堆,需要用户在自定义类型中提供<的重载
	priority_queue<Date> q1;
	q1.push(Date(2023, 5, 14));
	q1.push(Date(2023, 5, 16));
	q1.push(Date(2023, 5, 15));
	cout << q1.top() << endl;//结果:2023-5-16

	// 如果要创建小堆,需要用户提供>的重载
	priority_queue<Date, vector<Date>, greater<Date>> q2;
	q2.push(Date(2023, 5, 14));
	q2.push(Date(2023, 5, 16));
	q2.push(Date(2023, 5, 15));
	cout << q2.top() << endl;//结果:2023-5-14
}

我们看看下面这串代码:

void TestPriorityQueue3()
{
	priority_queue<Date*> q2;
	q2.push(new Date(2018, 10, 29));
	q2.push(new Date(2018, 10, 30));
	q2.push(new Date(2018, 10, 28));
	cout << *(q2.top()) << endl;
}

第一次运行结果:
在这里插入图片描述

第二次运行结果:
在这里插入图片描述

第三次运行结果:
在这里插入图片描述

我们会发现他每次的运行结果都是不一样的,是随机的,我们把代码改一改,再写一个仿函数:

class PDateLess
{
public:
	bool operator()(const Date* p1, const Date* p2)
	{
		return *p1 < *p2;
	}
};

class PDateGreater
{
public:
	bool operator()(const Date* p1, const Date* p2)
	{
		return *p1 > *p2;
	}
};
void TestPriorityQueue4()
{
	//priority_queue<Date*, vector<Date*>, PDateLess> q2;//结果:2018-10-30
	priority_queue<Date*, vector<Date*>, PDateGreater> q2;//结果:2018-10-28
	q2.push(new Date(2018, 10, 29));
	q2.push(new Date(2018, 10, 30));
	q2.push(new Date(2018, 10, 28));
	cout << *(q2.top()) << endl;
}

我们会发现:比较方式不同,结果也是不同的。
由此,我们可以得出优先级队列的一个优势:我们自己可以控制他的比较方式。

3、priority_queue的模拟实现

namespace hxj
{
	template<class T>
	struct less
	{
		bool operator()(const T& x, const T& y)
		{
			return x < y;
		}
	};

	template<class T>
	struct greater
	{
		bool operator()(const T& x, const T& y)
		{
			return x > y;
		}
	};

	// 大堆
	template<class T, class Container = vector<T>, class Comapre = less<T>>
	class priority_queue
	{
	public:
		void adjust_up(int child)
		{
			Comapre com;

			int parent = (child - 1) / 2;
			while (child > 0)
			{
				//if (_con[parent] < _con[child])
				//if (Comapre()(_con[parent], _con[child]))
				if (com(_con[parent], _con[child]))
				{
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

		void adjust_down(int parent)
		{
			size_t child = parent * 2 + 1;
			while (child < _con.size())
			{
				Comapre com;

				//if (child + 1 < _con.size() 
				//	&& _con[child] < _con[child + 1])
				if (child + 1 < _con.size()
					&& com(_con[child], _con[child + 1]))
				{
					++child;
				}

				//if (_con[parent] < _con[child])
				if (com(_con[parent], _con[child]))
				{
					swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}

		void push(const T& x)
		{
			_con.push_back(x);
			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/598746.html

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

相关文章

SpringBoot 学习笔记之 “异常处理”

&#x1f34f;&#x1f350;&#x1f34a;&#x1f351;&#x1f352;&#x1f353;&#x1fad0;&#x1f951;&#x1f34b;&#x1f349;&#x1f95d; 异常处理 文章目录 &#x1f34f; 错误处理1、默认规则2、定制错误处理逻辑3、异常处理自动配置原理4、异常处…

用Python发送通知到企业微信,实现消息推送

Hi&#xff0c;大家好&#xff0c;今天就介绍如何实现自动推送消息到企业微信&#xff0c;适合告警类型通知&#xff0c;非常方便。 在华为工作了10年的大佬出的Web自动化测试教程&#xff0c;华为现用技术教程&#xff01;_哔哩哔哩_bilibili在华为工作了10年的大佬出的Web自…

C++服务器框架开发6——日志系统LogFormatter/size_t学习

该专栏记录了在学习一个开发项目的过程中遇到的疑惑和问题。 其教学视频见&#xff1a;[C高级教程]从零开始开发服务器框架(sylar) 上一篇&#xff1a;C服务器框架开发5——日志系统LogAppender/IO类“3种stream”/双感叹号 C服务器框架开发6——日志系统logFormatter/size_t学…

【Python】深度理解Class类、Object类、Type元类;

详解Class类、Object类、Type元类 1.Class类、Object类、Type元类的表面关系2.Class、Object、Type解释1.1关系详解 2.Object类的默认方法作用详解2.2.1 init2.2.2 new2.2.3 repr2.2.4 提要&#xff1a;作为普通的Python开发者来讲&#xff0c;深入理解object、type不是必要的&…

ESP32设备驱动-MSA301加速计传感器驱动

MSA301加速计传感器驱动 文章目录 MSA301加速计传感器驱动1、MSA301介绍2、硬件准备3、软件准备4、驱动实现1、MSA301介绍 MSA301 是一款具有 I2C 数字输出的三轴低 g 加速度计,适用于消费类应用。 它具有 2g/4g/8g/16g 的动态用户可选满量程范围,并允许在 1Hz 至 500Hz 的…

Lombok 的正确使用姿势

文章目录 1.Lombok 是什么2.安装 Lombok3.Spring Boot 集成 Lombok4.使用 Lombok4.1 注解一览表4.2 部分使用介绍Getter(lazytrue)ValueBuilderSuperBuilderSneakyThrowsSlf4jCleanupNonNullWithSynchronizedval 在 Java 开发领域中&#xff0c;Lombok 插件已经成为一个非常流行…

OpenGL蓝宝书第八章学习笔记:基元处理之几何着色器

前言 本篇在讲什么 OpenGL蓝宝书第八章学习笔记之几何着色器 本篇适合什么 适合初学OpenGL的小白 本篇需要什么 对C语法有简单认知 对OpenGL有简单认知 最好是有OpenGL超级宝典蓝宝书 依赖Visual Studio编辑器 本篇的特色 具有全流程的图文教学 重实践&#xff0c…

使用scikit-learn和pandas学习线性回归

对于想深入了解线性回归的童鞋&#xff0c;这里给出一个完整的例子&#xff0c;详细学完这个例子&#xff0c;对用scikit-learn来运行线性回归&#xff0c;评估模型不会有什么问题了。 1. 获取数据&#xff0c;定义问题 没有数据&#xff0c;当然没法研究机器学习啦。这里我们用…

buuctf re入门题目解析

目录 1.easyre 2.reverse1 3.reverse2 4.内涵的软件 1.easyre 将exe文件放入ida&#xff0c;在主函数main中找到flag&#xff0c;此题结束 2.reverse1 打开主函数main&#xff0c;发现有一个跳转函数&#xff0c;双击打开 这句命令是将str1和str2的内容比较&#xff0c;当…

「C/C++」C/C++空指针void*

✨博客主页&#xff1a;何曾参静谧的博客 &#x1f4cc;文章专栏&#xff1a;「C/C」C/C程序设计 相关术语 void指针&#xff1a;是一种通用指针类型&#xff0c;可以指向任何类型的数据或对象。它不关心指向的数据或对象的类型&#xff0c;只关心指针本身的地址。因此&#xf…

性能测试—— 基础概念

目录 一、性能测试和功能测试的区别 二、性能测试衡量指标以及名称解释 1、并发用户数、系统用户数、在线用户数 2、响应时间、平均响应时间、请求响应时间 3、事务 4、点击率 5、吞吐量 6、思考时间 7、资源利用率 三、性能测试分类 1、一般性能测试 2、负载测试 …

【Python】函数 ③ ( 函数返回值定义语法 | 函数返回多个返回值 | 代码示例 )

文章目录 一、函数返回值定义语法二、函数返回多个返回值三、函数返回值代码示例 一、函数返回值定义语法 在 Python 函数中 , 通过 return 关键字 , 可以返回一个结果给调用者 , 这个返回结果就是 函数返回值 ; def 函数名(函数参数):"""函数文档字符串&#…

【C++】---模板初阶(超详练气篇)

个人主页&#xff1a;平行线也会相交&#x1f4aa; 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【C之路】&#x1f48c; 本专栏旨在记录C的学习路线&#xff0c;望对大家有所帮助&#x1f647;‍ 希望我们一起努力、成长&…

几种神经网络整定PID参数原理剖析及simulink案例仿真

目录 前言 1 基于单神经元自适应PID Simulink仿真分析 1.1 原理简介 1.1.1 无监督的Hebb学习 ​1.1.2 有监督的Delta学习 1.1.3 有监督的Hebb学习 1.1.4 改进的有监督Hebb学习 1.1.5 总结 1.2 simulink仿真分析 1.2.1 将权值作为状态变量仿真分析 1.2.2 利用局部变量…

Day6 不要二、把字符串转换成整数

✨个人主页&#xff1a; 北 海 &#x1f389;所属专栏&#xff1a; C/C相关题解 &#x1f383;操作环境&#xff1a; Visual Studio 2019 版本 16.11.17 文章目录 选择题1. 计算机组成原理 编程题1. 不要二2. 把字符串转换成为整数 选择题 1. 计算机组成原理 题目&#xff1a…

Atcoder beginner contest 303

A - Similar String AC代码&#xff1a; #include<iostream> #include<algorithm> #include<cstring> using namespace std; int main() {int n;cin >> n;string s, t;cin >> s >> t;bool flag true;for (int i 0; i < n; i) {if …

Nginx-Host绕过复现

目录 环境搭建&#xff1a; 第一种处理方式 第二种处理方式 第三种处理方式 原理依据&#xff1a;Nginx与PHP对Host处理方式不同 环境搭建&#xff1a; 1、提前安装完成nginxphpmysql&#xff0c;然后上传文件pwnhub到nginx/html下 2、修改nginx.conf配置文件&#xff1…

集权攻击系列:如何利用PAC新特性对抗黄金票据?

黄金票据简介 黄金票据是一种常见的域内权限维持手段&#xff0c;这种攻击主要是利用了Kerberos认证过程中TGT票据由KRBTGT用户的hash加密的特性&#xff0c;在掌握KRBTGT用户密码之后可以通过签发一张高权限用户的TGT票据&#xff0c;再利用这个TGT向KDC获取域内服务的ST来实…

ChatGPT 使用 拓展资料:2023年6月 吴恩达大咖Deeplearning.ai最新课程

ChatGPT 使用 拓展资料:2023年6月 吴恩达大咖Deeplearning.ai最新课程 Deeplearning.ai刚刚发布几个新的课程https://www.deeplearning.ai/short-courses/?utm_campaign=May%20Short%20Course%20Launch&utm_content=250952287&utm_medium=social&utm_source=link…

2023上半年软件设计师-试题详解与分析

目录 前言 上午题 计算机组成原理 信息安全 计算机相关法律 软件设计 语言处理 操作系统 软件工程 软件测试 面向对象编程 程序设计语言 数据库 数据结构与算法 计算机网络 计算机专业英语 下午题 数据流图 数据库 UML 算法与C语言 面向对象程序设计 前…