C++:STL--priority_queue

news2024/11/23 21:40:37

在这里插入图片描述

文章目录

  • 一.STL设计思想:容器适配器
      • STL--stack的代码设计
      • STL--queue的代码设计
      • stack和queue的默认容器适配器deque的数据结构解析
        • deque的存储结构示意图
  • 二.C++仿函数
      • 仿函数示例
  • 三.STL--priority_queue(优先级队列)
      • 1.C++优先级队列的数据结构
      • 2.priority_queue的实现框架
        • 比较函数(仿函数)的设计
        • priority_queue类模板实例化示例
      • 3.堆的向上调整接口实现
      • 4.堆的向下调整接口实现
      • 5.priority_queue类模板

一.STL设计思想:容器适配器

在STL的实现中,经常会复用已经完成实现的容器去实现另外一种容器(代码复用思想的具体体现),此时,前者(已经完成实现的容器)就称为后者(待实现的容器)的容器适配器,容器适配器的类型在代码设计中作为待实现容器的类模板参数.
比如,STL的stack和queue就是利用容器适配器思想来实现的

STL–stack的代码设计

template<class T, class container = deque<T>>
class stack
{
public:
	stack() 
	{}
	void push(const T& x) 
	{
		_c.push_back(x);
	}
	void pop() 
	{
		_c.pop_back();
	}
	T& top() 
	{ 
		return _c.back();
	}
	const T& top()const 
	{
		return _c.back();
	}
	size_t size()const 
	{
		return _c.size();
	}
	bool empty()const 
	{
		return _c.empty();
	}
private:
	container _c;
};

STL–queue的代码设计

template<class T, class container = deque<T>>
class queue
{
public:
	queue() 
	{}
	void push(const T& x) 
	{ 
		_c.push_back(x); 
	}
	void pop() 
	{ 
		_c.pop_front(); 
	}
	T& back() 
	{ 
		return _c.back(); 
	}
	const T& back()const 
	{ 
		return _c.back(); 
	}
	T& front() 
	{ 
		return _c.front(); 
	}
	const T& front()const 
	{ 
		return _c.front(); 
	}
	size_t size()const 
	{ 
		return _c.size(); 
	}
	bool empty()const 
	{ 
		return _c.empty(); 
	}
private:
	container _c;
};
  • 在这里插入图片描述
  • 根据stack和queue的实现框架可知,它们容器适配器必须支持数据的尾插,尾删, 头插,头删等等操作,用类型不合适的容器适配器去实例化stack和queue无法通过编译

stack和queue的默认容器适配器deque的数据结构解析

deque是STL标准库中的双端队列,其存储结构是用指针数组管理的一系列数组集合,它同时支持时间复杂度为O(1)的数据头插头删,尾插尾删操作

deque的存储结构示意图

  • 在这里插入图片描述
  • 分析deque的存储结构易知:deque的元素随机访问(下标访问)操作运算量较大,因此效率不高,而且在deque容器的中间位置插入或删除元素性能消耗非常巨大,而且deque的迭代器实现非常复杂
  • 因此有以下结论:
    • deque非常适合进行数据的头尾插入和删除操作,因此可以作为stack和queue的默认适配容器
    • 当使用场景涉及在容器的中间位置插入或删除元素时,首选list,使用deque效率会非常低
    • 当算法需要大量的元素随机访问操作时(比如快排),优先使用vector

二.C++仿函数

C++中的仿函数实质上是将()运算符重载封装在类中,使被封装起来的函数其可以依托于类对象作为"函数形参"传入其他函数中进行调用,C++设计仿函数的目的是为了取代C语言中的函数指针,有效地提高了代码的封装性

仿函数示例

  • 基于仿函数设计出来的两个数据比较函数
	template<class DataType>
	class less
	{
	public:
		bool operator()(const DataType& data1, const DataType& data2)
		{
			return data1 < data2;
		}
	};
	
	template<class DataType>
	class greater
	{
	public:
		bool operator()(const DataType& data1, const DataType& data2)
		{
			return data1 > data2;
		}
	};
  • 调用示例:
  • 在这里插入图片描述

三.STL–priority_queue(优先级队列)

1.C++优先级队列的数据结构

  • priority_queue的逻辑结构是一颗完全二叉树,其存储结构一般采用vector作为其默认容器适配器(容器适配器类型可由用户来决定,然而由于堆的上下调整算法涉及频繁的元素随机访问操作,因此大多数情况下vector都是priority_queue的最佳容器适配器)
    在这里插入图片描述

2.priority_queue的实现框架

	template<class DataType, class Container = std::vector<DataType>, class Compare = less<DataType>>
	class priority_queue
	{
	public:
		// 创造空的优先级队列
		priority_queue() {};
		//用迭代器区间建堆,采用元素向下调整法建堆
		template<class Iterator>
		priority_queue(Iterator first, Iterator last);
		//堆插入接口
		void push(const DataType& data);
		//堆顶元素出队接口
		void pop();

		//返回队列元素个数的接口
		size_t size()const;
		//队列判空接口
		bool empty()const;
		// 堆顶元素不允许修改,因为:堆顶元素修改可以会破坏堆的特性
		const DataType& top()const;

	private:
		//元素向上调整接口
		void AdjustUP(int child);
		//元素向下调整接口
		void AdjustDown(int parent);
		}
	private:
		//储存堆的物理容器
		Container _array;
	};
  • priority_queue类模板首部分析:
    在这里插入图片描述

比较函数(仿函数)的设计

	//用仿函数来实现比较器,用于控制堆的类型
	//用于建大堆的比较函数
	template<class DataType>
	class less
	{
	public:
		bool operator()(const DataType& data1, const DataType& data2) const
		{
			return data1 < data2;
		}
	};
	//用于建小堆的比较函数
	template<class DataType>
	class greater
	{
	public:
		bool operator()(const DataType& data1, const DataType& data2) const
		{
			return data1 > data2;
		}
	};
  • less<DataType>来实例化priority_queue的Compare模板参数则建立大根堆
  • greater<DataType>来实例化priority_queue的Compare模板参数则建立小根堆

priority_queue类模板实例化示例

在这里插入图片描述

3.堆的向上调整接口实现

  • 图解以小根堆为例:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
		//元素向上调整接口
		void AdjustUP(int child)
		{
			//创建数据比较函数(仿函数类)
			Compare comparator;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				if (comparator(_array[parent] , _array[child]))
				{
					std::swap(_array[child], _array[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

4.堆的向下调整接口实现

  • 堆的向下调整动图:
    在这里插入图片描述
		//元素向下调整接口
		void AdjustDown(int parent)
		{
			//创建数据比较函数(仿函数类)
			Compare comparator;
			//先取左孩子
			int child = 2 * parent + 1;
			while (child < size())
			{
				//取出左右孩子的较大值(或较小值)
				if (child + 1 < size() && comparator(_array[child] , _array[child + 1]))
				{
					child++;
				}
				if (comparator(_array[parent] , _array[child]))
				{
					std::swap(_array[parent], _array[child]);
					parent = child;
					child = 2 * parent + 1;
				}
				else
				{
					break;
				}
			}
		}

5.priority_queue类模板

namespace Mypriority_queue
{
	//用仿函数来实现比较器,用于控制堆的类型
	//用于建大堆的比较函数
	template<class DataType>
	class less
	{
	public:
		bool operator()(const DataType& data1, const DataType& data2) const
		{
			return data1 < data2;
		}
	};
	//用于建小堆的比较函数
	template<class DataType>
	class greater
	{
	public:
		bool operator()(const DataType& data1, const DataType& data2) const
		{
			return data1 > data2;
		}
	};


	template<class DataType, class Container = std::vector<DataType>, class Compare = less<DataType>>
	class priority_queue
	{
	public:
		// 创造空的优先级队列
		priority_queue() {};

		//用迭代器区间建堆,采用元素向下调整法建堆
		template<class Iterator>
		priority_queue(Iterator first, Iterator last)
		{
			//将元素都尾插到数组中
			for (auto it = first; it != last; ++it)
			{
				_array.push_back(*it);
			}

			//采用向下调整建堆,建堆时间复杂度为O(N);
			for (int tail = (size() - 1 - 1) / 2; tail >= 0; --tail)
			{
				AdjustDown(tail);
			}
		}

		//堆插入接口
		void push(const DataType& data)
		{
			//先将元素尾插到容器中,再执行元素向上调整
			_array.push_back(data);
			AdjustUP(size() - 1);
		}

		//堆顶元素出队接口
		void pop()
		{
			assert(!empty());
			//先将堆顶元素交换到堆尾,然后将堆尾元素移除,最后将堆顶元素向下调整恢复堆的结构
			std::swap(_array.front(), _array.back());
			_array.pop_back();
			AdjustDown(0);
		}

		//返回队列元素个数的接口
		size_t size()const
		{
			return _array.size();
		}

		//队列判空接口
		bool empty()const
		{
			return 0 == size();
		}
		// 堆顶元素不允许修改,因为:堆顶元素修改可以会破坏堆的特性
		const DataType& top()const
		{
			assert(!empty());
			return _array.front();
		}


	private:
		//元素向上调整接口
		void AdjustUP(int child)
		{
			Compare comparator;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				if (comparator(_array[parent] , _array[child]))
				{
					std::swap(_array[child], _array[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}
		//元素向下调整接口
		void AdjustDown(int parent)
		{
			Compare comparator;
			//先取左孩子
			int child = 2 * parent + 1;
			while (child < size())
			{
				//取出左右孩子的较大值
				if (child + 1 < size() && comparator(_array[child] , _array[child + 1]))
				{
					child++;
				}
				if (comparator(_array[parent] , _array[child]))
				{
					std::swap(_array[parent], _array[child]);
					parent = child;
					child = 2 * parent + 1;
				}
				else
				{
					break;
				}
			}
		}
	private:
		//储存堆的物理容器
		Container _array;
	};
}
  • 值得注意的是利用迭代器区间建堆的构造函数采用的建堆方式是向下调整建堆法,其时间复杂度为O(N),在众多算法实现中这是一个非常常用的建堆接口,关于堆的数据结构理论分析参见:堆的实现与建堆时间复杂度分析
    在这里插入图片描述

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

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

相关文章

chatgpt赋能python:Python中创建画布的函数——matplotlib

Python中创建画布的函数——matplotlib Python作为一种强大的编程语言&#xff0c;拥有许多重要且广泛应用的模块和库。其中&#xff0c;matplotlib是一种用于制作高质量的图形和图表的库&#xff0c;而创建画布的函数便是其基础功能之一。 什么是matplotlib&#xff1f; Ma…

C语言---初始C语言

1、初始C语言 1、编译器主要有&#xff1a;Clang、GCC、WIN-TC、MSVC、Turbo C等 什么是编译&#xff1f; test.c----------------------------->test.exe 这个过程需要经过编译、链接等过程&#xff0c;而众多编译器实现的功能就是把我们写的test.c进行编译。 2、VS20…

如何把“困在”内网的数据释放,进行安全的流转传输呢?

互联网大时代&#xff0c;数据的生产使用与互联网紧密相关&#xff0c;但数据安全和网络安全却既有联系又互不相同。数据安全和网络安全的突出区别是核心主体不同&#xff0c;数据安全关注的数据全生命周期的安全&#xff0c;而网络安全则是侧重保障网络体系和网络环境的安全性…

硬卷完了!低代码打怪升级进阶成神之路(2023年最新版)

一、背景 应用开发周期长一直是IT部门和业务部门面临的问题。 IT部门总是被新的应用需求弄得不堪重负。他们不可能完成业务部门想要完成的每一个项目。同时&#xff0c;业务部门的用户厌倦了等待&#xff0c;并开始完全绕过IT部门。 今天&#xff0c;我们来探索一下“低代码开发…

制药企业高效过滤器检漏参考法规、方法及操作步骤

对制药企业来讲&#xff0c;高效过滤器检漏主要是现场检漏&#xff0c;通过DOP法来发现滤器本身及运输、安装过程中可能存在的问题。常使用气溶胶光度计及多分散气溶胶进行检漏。依据的标准是2010药品GMP指南(测试方法采用ISO14644-3)。 对于制药企业来说&#xff0c;高效过滤器…

自动驾驶TPM技术杂谈 ———— 边缘检测

文章目录 介绍边缘检测与微分运算离散信号的差分滤波Robert算子Prewitt算子Sobel算子拉普拉斯算子 介绍 计算机视觉&#xff08;Computer Vision&#xff0c;CV&#xff09;是一门使用计算机模拟生物视觉的学科&#xff0c;目的是使用计算机代替人眼实现对目标的识别、分类、跟…

3.2. 数学类(Math、BigInteger、BigDecimal)

1. Math类 Math类提供了一些基本的数学函数&#xff0c;如求平方根、绝对值、三角函数等。它是一个final类&#xff0c;并且所有的方法都是static的&#xff0c;因此无需创建对象&#xff0c;直接使用类名调用方法即可。 以下是Math类的一些常用方法&#xff1a; abs(double…

抖音seo源码-抖音搜索源码-抖音下拉词-抖音关键词排名系统搭建

为了优化抖音平台上的内容&#xff0c;开发抖音关键词排名系统成为了必要的措施。该系统可以针对搜索结果和下拉词进行分析&#xff0c;为用户提供更准确的搜索结果。为实现这一目标&#xff0c;开发团队进行了大量的市场调查和用户研究。 在开发过程中&#xff0c;团队利用了…

mysql8+忘记密码的详细解决方法

mysql8忘记密码的详细解决方法 不同的版本&#xff0c;可能处理的方式不一样&#xff0c;这里说一下8以上的版本处理密码忘记的问题&#xff0c;windows系统。 一.问题&#xff1a; 太久没用mysql &#xff0c;忘记了原先的root密码 二&#xff1a;解决 1.关闭mysql服务,我的…

代码随想录算法训练营第四十八天 | 力扣 198.打家劫舍, 213.打家劫舍II, 337.打家劫舍III

198.打家劫舍 题目 198. 打家劫舍 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警…

word文档生成PDF文档时候自动生成书签方法

0 Preface/Foreword 在日常工作中&#xff0c;经常需要写技术文档&#xff0c;为了排版美观&#xff0c;一般会选择word&#xff0c;这样就可以生成目录。 word文件可以很方便生产PDF文档&#xff0c;方便分享给同事。 在阅读PDF文档时&#xff0c;看到有些PDF文档在左侧有一…

Kafka入门(安装和SpringBoot整合)

文章目录 一、Docker安装Kafka1. 创建网络2. 安装zookeeper3. 安装Kafka 二、Kafka介绍1. Kafka简介 三、SpringBoot整合Kafka1. 引入pom依赖2. application.propertise配置3. Hello Kafka(Producer)4. Consumer Kafka5. 带回调的生产者6. 自定义分区器7. kafka事务提交8. 指定…

如何将 O2OA (翱途) 集成到阿里钉钉

O2OA 平台拥有配套的原生开发的安卓和 IOS 移动 APP&#xff0c;可以以微应用的方式集成到阿里钉钉&#xff0c;同步钉钉的企业通讯录作为本地组织人员架构&#xff0c;并且可以将待办等通知直接推送到钉钉进行消息提醒。本篇主要介绍如何将 O2OA 集成到阿里钉钉实现钉钉办公。…

欧科云链(01499.HK)成格林威治经济论坛钻石级行业独家合作伙伴

5月30日讯&#xff0c;欧科云链控股有限公司&#xff08;“欧科云链控股”&#xff0c;1499.HK&#xff09;官宣成为全球高端经济峰会格林威治经济论坛(Greenwich Economic Forum&#xff0c;下称GEF论坛)的钻石级行业独家合作伙伴。该论坛将于6月15日至16日&#xff0c;首次在…

【维生素C语言】附录:Github 使用教学

&#x1f451; 全新Python高级软件实践专栏&#xff1a; 一起玩蛇啊 &#x1f449; 《一起玩蛇》&#x1f40d; &#x1f4ad; 写在前面&#xff1a;本章我们将介绍 Git 的基本使用方法&#xff0c;包括注册 GitHub 账号、设置 Git、创建本地存储库、复制本地存储库、导入远程…

electron24整合vite4+vue3创建跨端桌面程序

基于Electron集成Vite4.x构建桌面端exe应用 electron24-vite4-vue3 运用最新版本electron结合vite4.x创建vue3桌面端应用程序。 // 版本信息 vite: ^4.3.2 vue: ^3.2.47 electron: ^24.4.0 electron-builder: ^23.6.0创建vitevue3项目 // 初始化项目 npm create vitelatest el…

Echarts绘制K线图,文末源码地址!

文章目录 K线图Apache Echarts绘制K线图完整源码地址 本文中仅展示部分关键代码&#xff0c;文末有完整源码地址&#xff0c;欢迎下载&#xff01; K线图 K线图是一种常见的股票价格走势图表&#xff0c;它是用于显示股票价格变化的一种图表形式。K线图以日、周、月等周期为单…

聊聊分布式解决方案Saga模式

Saga模式 Saga模式使用一系列本地事务来提供事务管理&#xff0c;而一个本地事务对应一个Saga参与者&#xff0c;在Saga流程里面每一个本地事务只操作本地数据库&#xff0c;然后通过消息或事件来触发下一个本地事务&#xff0c;如果其中一个本地事务失败了&#xff0c;Saga就…

一文搞懂激活函数(Sigmoid/ReLU/LeakyReLU/PReLU/ELU)

深度学习算法之前的机器学习算法&#xff0c;并不需要对训练数据作概率统计上的假设&#xff1b;但为了让深度学习算法有更好的性能&#xff0c;需要满足的关键要素之一&#xff0c;就是&#xff1a;网络的输入数据服从特定的分布&#xff1a; 数据分布应该是零均值化的&#…

内核调试环境搭建

内核调试环境搭建 目录 经过测试好用的内核调试环境搭建过程ubuntu和linux版本 查看commit所属的内核版本查看Ubuntu版本号等信息 下载与安装内核 下载内核ubuntu更换内核手动下载并切换到指定源码用apt下载源码使用git下载对应版本 编译并安装linux内核&#xff08;使用linu…