priority_queue

news2024/11/25 15:00:30

priority_queue:优先队列
头文件还是 < queue>
本质就是堆:完全二叉树 + 条件(任意节点都比其孩子大(大根堆))
在这里插入图片描述
priority_queue的默认比较是less,但是建出来的是大根堆;sort排序算法用less,得出的是升序

可以发现对于sort和priority_queue,使用greater和less类模板是结果不同的。

  • 主要原因是因为priority_queue的内部实现方法是堆,less对应的是大顶堆。在此排序下调用top()得到的是堆顶,也就是取值时是从大到小。push对应的底层函数是push_heap(),每次添加元素入堆时,在默认情况下添加进去的数据作为较小值入堆。
  • 顺序真正不同的根本原因
    堆的内部实现是vector,每次出堆的时候 实际上是堆顶元素和最后一个元素互换(把最大元素沉到数组末端)。那么实际上假如没有出堆这一个过程而是继续将数据缓存在vector中,所有元素出堆后,形成的数组就是升序的。只是由于出堆这一过程导致了元素出堆反序了,相当于逆序输出。

默认是建大堆:priority_queue<int> first;
如果要建小堆,要给全模板参数

priority_queue<int, vector<int>, greater<int>> third

优先队列如果这么用就显得没有什么必要了,一般来讲都是存储自定义类型,写仿函数作为优先级比较哦

#include<iostream>
#include<queue>
#include<functional>
#include<vector>

using namespace std;

int main()
{
	int arr[] = { 10,99,123,213,42,1,7,5 };
	sort(arr, arr + (sizeof(arr) / 4),less<int>());
	priority_queue<int> q(arr,arr+(sizeof(arr)/4));//模板只传一个参数时,后面两个参数按默认参数来,默认比较方式为less,大根堆     其他的less是升序
	priority_queue<int, vector<int>,greater<int>> q2(arr,arr+(sizeof(arr)/4));//当
	while (!q.empty())
	{
		cout << "q.top()=" << q.top() <<"\t" << "q.size()=" << q.size() << endl;
		q.pop();
	}
	while (!q2.empty())
	{
		cout << "q2.top()=" << q2.top() << "\t" << "q2.size()=" << q2.size() << endl;
		q2.pop();
	}
	return 0;
}

可以给operator<在自定义类中对比较运算符重载,这样默认的模版调用less的<时就会调用这个重载的比较运算符函数,或者在类外定义仿函数,用模版参数传参

/*
template struct less : binary_function <T, T, bool> {
bool operator() (const T& x, const T& y) const { return x < y; }
};

为何要重载 < 运算符,因为pripority_queue的默认参数第三个是less模板类(按升序比较排序),
观察模板可以通过重载 < 运算符来实现自定义类型的比较,也可以重写一个类,在类中重载函数调用运算符 () 仿函数来实现
上面是模板less,将Date替换T,则会出现两个Date对象比较,
因为Date是自定义类型所以要进行<运算符重载才能进行比较,
这样在只传一个Date参数时 priority_queue<Date> q 可以运行,
而要进行大堆创建就得
priority_queue<Date,vector<Date>,greater<Date>> q
并且还要进行 > 运算符重载
*

class Date {
	friend class Cmp;
public:
	Date(int y, int m, int d)
	{
		m_year = y;
		m_month = m;
		m_day = d;
	}
	void show()
	{
		cout << this->m_year << "/" << this->m_month << "/" << this->m_day << endl;
	}
	/*
	template <class T> struct less : binary_function <T, T, bool> {
		bool operator() (const T& x, const T& y) const { return x < y; }
	};
	
	为何要重载 < 运算符,因为pripority_queue的默认参数第三个是less模板类(按升序比较排序),
	观察模板可以通过重载 < 运算符来实现自定义类型的比较,也可以重写一个类,在类中重载函数调用运算符 () 仿函数来实现
	上面是模板less,将Date替换T,则会出现两个Date对象比较,
	因为Date是自定义类型所以要进行<运算符重载才能进行比较,
	这样在只传一个Date参数时 priority_queue<Date> q 可以运行,
	而要进行大堆创建就得
	priority_queue<Date,vector<Date>,greater<Date>> q
	并且还要进行 > 运算符重载
	*/
	bool operator<(const Date& d)
	{
		if((m_year<d.m_year)||(m_year==d.m_year&&m_month<d.m_month)||(m_day==d.m_day&&m_day < d.m_day))
			return true;
		return false;
	}
	bool operator()(const Date& d)const
	{
		if ((m_year < d.m_year) || (m_year == d.m_year && m_month < d.m_month) || (m_day == d.m_day && m_day < d.m_day))
			return true;
		return false;
	}
private:
	int m_year;
	int m_month;
	int m_day;
};
class Cmp {//在类中重载函数调用运算符 () 仿函数来实现,因为Date类中成员为private所以要在类Date中声明Cmp为friend
public:
	bool operator()(const Date& x, const Date& y)
	{
		if ((x.m_year < y.m_year) || (x.m_year == y.m_year && x.m_month < y.m_month) || (x.m_day == y.m_day && x.m_day < y.m_day))
			return true;
		return false;
	}
};
int main()
{
	Date d3(2023, 1, 10);
	Date d2(2016, 5, 1);
	Date d1(2011, 9, 30);
	priority_queue<Date,vector<Date>,Cmp> q;
	q.push(d1);
	q.push(d2);
	q.push(d3);
	while (!q.empty())
	{
		auto x=q.top();
		x.show();
		q.pop();
	}
	
	return 0;
}

优先队列priority_queue,虽然是队列,但是没有front,back方法
在这里插入图片描述
反倒像栈一样有个top方法,并且这个top还是const

const value_type& top() const;

模拟实现:

差不多就是用vector封装一个堆,再加上比较器类的仿函数

#pragma once
#include<vector>

namespace gyx
{
	template<class T>
	struct Less
	{
		bool operator()(const T& left, const T& right)
		{
			return left < right;
		}
	};

	template<class T>
	struct Greater
	{
		bool operator()(const T& left, const T& right)
		{
			return left > right;
		}
	};

	template<class T,class Containter=std::vector<T>,class Compare=Less<T>>
	class priority_queue
	{
	private:
		Containter c;
	public:
		priority_queue(){}

		template<class Iterator>
		priority_queue(Iterator first, Iterator last)
			:c(first, last)//给成员容器进行迭代器构造
		{
			int last_not_leaf = (c.size() - 2) / 2;//最后一个非叶子结点
			for (int i = last_not_leaf; i >= 0; i--)
				adjustdown(i);
			//对每一个子树进行向下调整,顺序是先从最末尾的根,直到root
		}

		void push(const T& val)
		{
			c.push_back(val);
			adjustup();
		}

		void pop()
		{
			if (empty())
				return;
			//堆的删除,是把堆顶元素和堆的最后一个元素交换,然后指针前移,再向下调整
			std::swap(c.front(),c.back());//这里的front和back是底层vector的方法,不是优先队列的方法
			c.pop_back();
			adjustdown(0);
		}
		const T& top()const{ return c.front(); }
		int size()const{ return c.size(); }
		bool empty()const{ return c.empty(); }

	private:
		void adjustdown(int parent)//每次传入的都是一个非叶结点
		{
			//向下调整,先进行
			//int size = size();
			int child = parent * 2 + 1;
			while (child < size() )
			{
				Compare com;//模版参数传的比较器类仿函数
				if (child + 1 < size() && com(c[child], c[child + 1]))
					child += 1;

				if (com(c[parent], c[child]))
				{
					swap(c[parent], c[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else return;//说明这个子树是满足堆要求的
			}
		}

		void adjustup()//向上调整是,插入新元素时进行的调整
		{
			int child = size() - 1;
			int parent = (child - 1) / 2;

			Compare com;

			while (child)
			{
				if (com(c[parent], c[child]))
				{
					std::swap(c[parent], c[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else return;
			}
		}
	};
}

在前面实现stack和queue使用的vecotr和list,但实际stl中是用双端队列deque来实现的
deque
STL的deque是C++标准库中的双端队列容器,提供了快速的在两端插入与删除元素的操作,并且支持随机访问、迭代器等功能。deque采用了分块技术实现,在内存中是由多个连续的定长块组成的,每个块都可以容纳多个元素。
这种实现方式使得deque既能在常数时间内进行头尾插入删除操作,又能以近似常数时间访问任意位置的元素。

  • STL的deque采用了一种类似于多个定长数组组成的数据结构,每个数组被称为一个缓冲区(buffer)。这些缓冲区以连续的方式排列在一起,并使用指针来保持它们的连接,从而形成整体的容器结构。
  • deque的实现通常会预先分配多个缓冲区,当需要插入新元素时,它会在队列的两端查找邻近的缓冲区并进行操作。如果某一端的缓冲区已满,则可以从另一端的缓冲区中借用一些空间,或者重新分配一些新的缓冲区来扩充容器大小。
  • 这种实现方式使得deque拥有了优秀的插入和删除效率,同时也支持快速的随机访问操作,因为我们可以通过指针来直接跳转到任意位置的缓冲区并访问其中的元素。

适用场景:
使用哪种数据结构取决于具体的场景和需求。虽然deque有许多优点,但它也有一些缺点需要考虑。
首先,deque的空间利用率可能不如vector高,因为它存储元素所需的所有缓冲区的大小总和通常会超过实际存储的元素数量,从而导致一定程度的空间浪费。
其次,由于deque的底层结构比较复杂,因此在某些情况下它可能会比其他容器类型产生额外的性能开销。
因此,是否应该使用deque,还需要根据具体应用场景和需求进行选择。如果需要在队列的两端进行高效的插入和删除操作,且同时需要支持随机访问操作,那么deque就是一个不错的选择。不过如果只需要允许在队列头尾进行一端插入和删除操作的话,那么使用更简单的std::queue可能更加合适。

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

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

相关文章

顺序表的基本操作(初始化,增,删,查,改等等)

1.线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使 用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串...线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条直线…

智能算法系列之蚁群算法

本博客封面由ChatGPT DALLE 2共同创作而成。 文章目录 前言1. 算法思想2. 算法流程3. 细节梳理4. 算法实现4.1 问题场景4.2 代码实现 代码仓库&#xff1a;IALib[GitHub] 前言 本篇是智能算法(Python复现)专栏的第五篇文章&#xff0c;主要介绍蚁群算法(Ant Colony Optimizati…

cmd@快捷键方式@静默执行命令

文章目录 ref快捷方式执行命令行或打开文件eg:直接打开某个文件 创建快捷方式eg:快捷方式运行命令 ref How can I execute a Windows command line in background? - Super Userstbrenner/SilentCMD: SilentCMD executes a batch file without opening the command prompt wi…

如何用100天时间,让CSDN的粉丝数从0狂飙到10000

2022年10月7日&#xff0c;正式开通了CSDN账号。但因为工作忙的原因&#xff0c;一直没有时间写博客文章&#xff0c;也没有投入精力在CSDN上。理所当然的&#xff0c;我的粉丝数量很稳定&#xff0c;一直保持着0的记录。 2023年春节假期过后&#xff0c;有点空闲时间了&#x…

Tre靶场通关过程(linpeas使用+启动项编辑器提权)

Tre靶场通关 通过信息收集获得到了普通用户账号密码&#xff0c;利用PEASS-ng的linpeas脚本进行提权的信息收集&#xff0c;根据已有信息进行提权。 靶机下载地址&#xff1a; https://download.vulnhub.com/tre/Tre.zip 信息收集 靶机IP探测&#xff1a;192.168.0.129 a…

java多线程下

ThreadLocal ThreadLocal 有什么用&#xff1f;通常情况下&#xff0c;我们创建的变量是可以被任何一个线程访问并修改的。如果想实现每一个线程都有自己的专属本地变量该如何解决呢&#xff1f;JDK 中自带的ThreadLocal类正是为了解决这样的问题。 ThreadLocal类主要解决的就…

解释表情包This code will never do anything!

目录 解释一下下面这段代码 #include int main(){ while (1) ;} void unreachable(){ std::cout <<"Hello world!"<;}<> 解释一下下面这段代码 $ clang loop.cpp -01 -Wall -o loop $ ./loop Hello world! 解释一下下面这段代码 #include <iostre…

python面试题

文章目录 赋值、深拷贝和浅拷贝有什么区别&#xff1f;元组和列表有什么不同&#xff1f;和is有什么不同&#xff1f;集合怎么转字典&#xff1f;字典怎么遍历&#xff1f;如何在Python中实现多线程&#xff1f;如何实现tuple和list的转换&#xff1f;实现删除一个list里面的重…

厉害的人是搭建平台的人,少数人

牛人是搭建平台的人&#xff0c;是少数人 创建平台才有难度 趣讲大白话&#xff1a;多数人的成就是借平台之力 【趣讲信息科技157期】 **************************** 认识清楚平台能力和个人能力 创建阿里巴巴公司太难 多数人是借阿里巴巴平台之力成就的 离开一个成功的平台&a…

汽车之家股票回购速度远低于预期,面临严重的资本投资风险

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 汽车之家的估值 基于对汽车之家&#xff08;ATHM&#xff09;2023财年非GAAP调整后每股收益2.55美元的普遍预测&#xff0c;市场给予汽车之家目前的估值约为2023财年预期正常化市盈率的13倍&#xff0c;猛兽财经认为这个市…

libevent高并发网络编程 - 01_libevent事件Event处理

文章目录 1. libevent事件驱动和事件处理简介2. 事件状态分析3. 事件Event常用API3.1 event_base_new()3.2 event_base_free()3.3 event_new()3.4 event_add()3.5 event_del()3.6 event_free()3.7 event_base_dispatch()3.8 event_base_loopbreak()3.9 evsignal_new()3.10 even…

继承与虚函数练习

Tip1 基类私有成员变量在子类中都不能直接访问&#xff0c;不是因为没有被子类继承&#xff0c;而是权限问题 Tip2 满足多态的父子对象&#xff0c;父类对象和子类对象前4个字节都是虚表指针&#xff08;vs2019下&#xff09;&#xff0c;父类与子类指向的是各自的虚表。 Tip…

云计算中的容器技术及其实践案例

第一章&#xff1a;什么是容器技术 随着云计算和DevOps的普及&#xff0c;容器技术在IT行业中越来越受到关注。容器是一种轻量级、可移植、可扩展的应用程序封装技术&#xff0c;可以将应用程序及其所有依赖项打包到一个独立的可执行文件中。相对于虚拟机技术&#xff0c;容器技…

无界AI绘画基础教程,和Midjourney以及Stable Diffusion哪个更好用?

本教程收集于&#xff1a;AIGC从入门到精通教程汇总 简单的总结 Midjourney&#xff0c;Stable Diffusion&#xff0c;无界AI的区别&#xff1f; Midjourney&#xff0c;收费&#xff0c;上手容易&#xff0c;做出来高精度的图需要自己掌握好咒语。咒语写不好&#xff0c;像…

【LLM大模型】LLM模型指令微调(更新中)

note 文章目录 note零、AIGC生成式模型1. 核心要素2. LLM evolutionary tree 二、LLM大模型1. ChatGLM&#xff08;1&#xff09;GLM-130B&#xff08;2&#xff09;ChatGLM-6B 2. LLaMA3. Chinese-LLaMA-Alpace4. Bloom5. PaLM 三、模型指令微调Reference 零、AIGC生成式模型 …

算法记录 | Day53 动态规划

1143.最长公共子序列 思路&#xff1a; 本题和动态规划&#xff1a;718. 最长重复子数组 (opens new window)区别在于这里不要求是连续的了&#xff0c;但要有相对顺序&#xff0c;即&#xff1a;“ace” 是 “abcde” 的子序列&#xff0c;但 “aec” 不是 “abcde” 的子序…

搭建DHCP、PXE、DNS、HTTP以及NFS服务综合实验的超详细讲解

文章目录 1.实验要求2.实验步骤2.1 步骤解答问题&#xff08;1&#xff09;2.1 步骤解答问题&#xff08;2&#xff09;2.1 步骤解答问题&#xff08;3&#xff09;2.1 步骤解答问题&#xff08;4&#xff09;2.1 步骤解答问题&#xff08;5&#xff09; 1.实验要求 &#xff…

Hadoop入门篇01---基础概念和部署教程

Hadoop入门篇01---基础概念和部署教程 Hadoop是什么Hadoop发展史Hadoop特点有哪些Hadoop版本Hadoop架构Hadoop 3.0新特性 Hadoop集群搭建集群简介集群部署方式standalone mode&#xff08;独立模式&#xff09;Pseudo-Distributed mode&#xff08;伪分布式模式&#xff09;Clu…

webpack的核心概念分别是什么,如何理解

这篇文章主要介绍了 title &#xff0c;小编觉得挺不错的&#xff0c;现在分享给大家&#xff0c;也给大家做个参考&#xff0c;希望大家通过这篇文章可以有所收获。 webpack 是一种前端资源构建工具&#xff0c;一个静态模块打包器&#xff08;module bundler&#xff09;&…

UE5.1.1C++从0开始(4.虚幻的接口以及交互功能)

这一个章节对于第一次接触虚幻的人来说可以说是最绕的一个点&#xff0c;因为老师突然给你塞了很多的概念&#xff0c;对于这一块的学习&#xff0c;我个人的推荐是&#xff1a;先把蓝图搞明白了&#xff0c;再对应到C的代码中&#xff0c;不然一定会被整的晕头转向。还是&…