STL —— priority_queue

news2025/3/14 22:15:47

图片名称

博主首页: 有趣的中国人
 

专栏首页: C++专栏
 


 

本篇文章主要讲解 priority_queue 的相关内容

目录

1. 优先级队列简介

基本操作

 2. 模拟实现

2.1 入队操作

2.2 出队操作

2.3 访问队列顶部元素

2.4 判断优先队列是否为空

2.5 获取优先队列的大小

3. 仿函数

仿函数的特点

使用场景

示例代码

仿函数替代函数指针

4.利用仿函数实现优先级队列 

5. 有关自定义类型的排序


 

1. 优先级队列简介

std::priority_queue 是一个模板类,定义在 <queue> 头文件中,它基于堆(heap)数据结构来实现优先队列的功能。默认情况下,std::priority_queue 使用 std::vector 作为其底层容器,并且使用比较器(默认是 std::less)来决定元素的优先级顺序。 

基本操作

  1. 入队操作: 使用 push() 成员函数将元素推入优先队列中。

    std::priority_queue<int> myPriorityQueue;
    myPriorityQueue.push(10);
  2. 出队操作: 使用 pop() 成员函数从优先队列中移除顶部(优先级最高)的元素。

    myPriorityQueue.pop();
    
  3. 访问队列顶部元素: 使用 top() 成员函数获取优先队列顶部(优先级最高)的元素,但不会将其从队列中移除。

    int topElement = myPriorityQueue.top();
    
  4. 判断优先队列是否为空: 使用 empty() 成员函数检查优先队列是否为空。

    if (!myPriorityQueue.empty()) {
        // 优先队列不为空
    }
    
  5. 获取优先队列的大小: 使用 size() 成员函数获取优先队列中元素的数量。

    int queueSize = myPriorityQueue.size();
    

 2. 模拟实现

其模拟实现的方式也是按照容器适配器的模式来完成的,刚才提到过其底层是堆的形式,那么只需要用vector来模拟实现即可

2.1 入队操作

void adjust_up()
{
	int child = _con.size() - 1;
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (_con[parent] < _con[child])
		{
			swap(_con[parent], _con[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
// 大堆
void push(const T& val)
{
	_con.push_back(val);
	adjust_up();
}

2.2 出队操作

void adjust_down()
{
	int parent = 0;
	int child = (parent * 2) + 1;
	while (child < _con.size())
	{
		if (child + 1 < size() && (_con[child] < _con[child + 1]))
		{
			++child;
		}
		if (_con[parent] < _con[child])
		{
			swap(_con[parent], _con[child]);
			parent = child;
			child = (parent * 2) + 1;
		}
		else
		{
			break;
		}
	}
}

void pop()
{
	swap(_con[0], _con[_con.size() - 1]);
	_con.pop_back();
	adjust_down();
}

2.3 访问队列顶部元素

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

2.4 判断优先队列是否为空

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

2.5 获取优先队列的大小

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

3. 仿函数

仿函数是C++中的一个概念,它实际上是一个类或结构体,但其行为类似于函数。仿函数可以像函数一样被调用,因此也被称为函数对象。

仿函数的特点

  1. 类似函数: 仿函数实际上是一个类对象,但其重载了函数调用运算符 operator(),使得它可以像函数一样被调用。

  2. 灵活性: 仿函数可以包含状态,因此可以捕获和存储额外的信息,而这在普通函数中可能很难实现。

  3. 可定制性: 仿函数可以根据需要进行定制,比如可以重载不同的函数调用运算符,或者添加额外的成员函数。

使用场景

  1. 作为函数对象传递: 仿函数可以作为参数传递给算法函数,这在STL中非常常见。比如,std::sort 函数可以接受一个仿函数来定义排序的顺序。

  2. 定制排序规则: 当需要对容器中的元素进行排序时,可以使用仿函数来定义排序规则,比如按照自定义的比较方式排序。

  3. 条件判断: 仿函数可以用于条件判断,例如在算法中过滤元素时。

示例代码

下面是一个简单的示例,演示了如何定义和使用一个简单的仿函数:

#include <iostream>

// 定义一个简单的仿函数
struct MyFunctor {
    void operator()(int x) const {
        std::cout << "Value: " << x << std::endl;
    }
};

int main() {
    MyFunctor myFunc;

    // 调用仿函数
    myFunc(10);

    return 0;
}

仿函数替代函数指针

在许多情况下,仿函数可以替代函数指针,并提供更多的灵活性和可扩展性。 

我们知道在C语言中的qsort中,只需要给出两个元素的比较大小的方式,就可以传递函数指针来进行大小的排序,然而在C++中,我们可以传递仿函数,并调用算法库中的sort来进行排序,例如以下的代码:

#include <iostream>
#include <vector>
#include <algorithm>

// 定义一个比较器仿函数
struct MyComparator 
{
    bool operator()(int a, int b) const 
    {
        return a % 10 < b % 10; // 按照个位数进行排序
    }
};

int main() 
{
    std::vector<int> nums = {15, 30, 25, 12, 7};

    // 使用仿函数进行排序
    // 传匿名对象
    std::sort(nums.begin(), nums.end(), MyComparator());

    // 打印排序后的结果
    for (int num : nums) 
    {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}


4.利用仿函数实现优先级队列 

按照这样的逻辑,我们就可以用仿函数来实现优先级队列,

  • 如果按照升序排序,建小堆,传greater比较方式;
  • 如果按照降序排序,建大堆,传less比较方式。
template<class T>
class less
{
public:
	bool operator()(const T& left, const T& right)
	{
		return left < right;
	}
};

template<class T>
class greater
{
public:
	bool operator()(const T& left, const T& right)
	{
		return left > right;
	}
};

template<class T, class Container = vector<T>, class Compare = greater<T>>
class priority_queue
{
public:
	void adjust_up()
	{
		Compare com;
		int child = _con.size() - 1;
		int 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 push(const T& val)
	{
		_con.push_back(val);
		adjust_up();
	}

	void adjust_down()
	{
		Compare com;
		int parent = 0;
		int child = (parent * 2) + 1;
		while (child < _con.size())
		{
			if (child + 1 < 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;
			}
		}
	}

	void pop()
	{
		swap(_con[0], _con[_con.size() - 1]);
		_con.pop_back();
		adjust_down();
	}

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

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

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

private:
	Container _con;
};

5. 有关自定义类型的排序

在很多情况下,我们需要对一个自定义类型按照某种形式进行排序,例如,对于一种商品,可能对他的评价、价格、销量等情况进行排序,这个时候我们就可以运用仿函数了。

struct Goods
{
	string _name; // 名字
	double _price; // 价格
	int _evaluate; // 评价

	Goods(const char* str, double price, int evaluate)
		:_name(str)
		, _price(price)
		, _evaluate(evaluate)
	{}
};

struct compare_price_less
{
	bool operator()(const Goods& gdp1, const Goods& gdp2)
	{
		return gdp1._price < gdp2._price;
	}
};

struct compare_evaluate_less
{
	bool operator()(const Goods& gde1, const Goods& gde2)
	{
		return gde1._evaluate < gde2._evaluate;
	}
};

struct compare_name_greater
{
	bool operator()(const Goods& gdn1, const Goods& gdn2)
	{
		return gdn1._name > gdn2._name;
	}
};

int main()
{
	vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,
	3 }, { "菠萝", 1.5, 4 } };

	sort(v.begin(), v.end(), compare_name_greater());
	
	sort(v.begin(), v.end(), compare_evaluate_less());

	sort(v.begin(), v.end(), compare_price_less());
	return 0;
}

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

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

相关文章

分布式向量数据库-安装部署

下载 GitHub - pgvector/pgvector: Open-source vector similarity search for Postgres 源码编译 ##文件解压缩 unzip pgvector-0.6.2.zip ##编译 make && make install 功能验证 #安装扩展CREATE EXTENSION vector;#创建测试表CREATE TABLE items (id bigseri…

mysql题目1

tj11: ​ select * from t_student where grade 大一 and major 软件工程 ​ tj12: SELECTt_student.name, count(t_choice.cid)FROMt_choiceINNER JOINt_courseON t_choice.cid t_course.idINNER JOINt_studentON t_choice.sid t_student.id GROUP BYt_choice.sid HAVIN…

【Unity 实用工具篇】 | UIEffect 实现一系列UGUI特效,灰度、负片、像素化特效

前言 【Unity 实用工具篇】 | UIEffect 实现一系列UGUI特效&#xff0c;灰度、负片、像素化特效一、UGUI特效插件&#xff1a;UIEffect1.1 介绍1.2 效果展示1.3 使用说明及下载 二、组件属性面板三、代码操作组件四、组件常用方法示例4.1 使用灰度特效做头像(关卡)选择 总结 前…

win11电脑驱动怎么更新,windows11更新驱动

驱动是指计算机里软件的程序,硬件的运作离不开驱动的支持,因为驱动就是使得硬件和电脑系统沟通的桥梁。既然驱动如此重要,那么不装肯定不行,如果有问题,也要及时地修复和更新。最近,有位win11用户,想要了解win11电脑驱动怎么更新?接下来,教程会带来两种更新win11驱动的…

CodeForce[1500-2000]——1948D Tandem Repeats?

大概题目意思就是&#xff1a;给你一个只有小写字母和问号的字符串&#xff0c;可以在头或尾删除任意长度&#xff0c;得到一个字串&#xff0c;并且该字串要满足长度为偶数&#xff0c;前一半和后一半&#xff08;问号可以匹配任意字符&#xff09;相等&#xff0c;求这样的字…

专治Java底子差,线程操作篇(2)

&#x1f497;推荐阅读文章&#x1f497; &#x1f338;JavaSE系列&#x1f338;&#x1f449;1️⃣《JavaSE系列教程》&#x1f33a;MySQL系列&#x1f33a;&#x1f449;2️⃣《MySQL系列教程》&#x1f340;JavaWeb系列&#x1f340;&#x1f449;3️⃣《JavaWeb系列教程》…

2024五一杯数学建模A题B题C题思路汇总分析

文章目录 1 赛题思路2 比赛日期和时间3 组织机构4 建模常见问题类型4.1 分类问题4.2 优化问题4.3 预测问题4.4 评价问题 5 建模资料 1 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 2 比赛日期和时间 报名截止时间&#xff1a;2024…

设计模式——2_9 模版方法(Template Method)

人们往往把任性也叫做自由&#xff0c;但是任性只是非理性的自由&#xff0c;人性的选择和自决都不是出于意志的理性&#xff0c;而是出于偶然的动机以及这种动机对感性外在世界的依赖 ——黑格尔 文章目录 定义图纸一个例子&#xff1a;从文件中获取信息分几步&#xff1f;Rea…

Hive概述与基本操作

一、Hive基本概念 1.什么是hive? &#xff08;1&#xff09;hive是数据仓库建模的工具之一 &#xff08;2&#xff09;可以向hive传入一条交互式的sql,在海量数据中查询分析得到结果的平台 2.Hive简介 Hive本质是将SQL转换为MapReduce的任务进行运算&#xff0c;底层由HDFS…

经典文献阅读之--A Survey on Generative Diffusion Models(扩散模型最新综述)

0. 简介 本文综述了深度生成模型&#xff0c;特别是扩散模型(Diffusion model)&#xff0c;如何赋予机器类似人类的想象力。扩散模型在生成逼真样本方面显示出巨大潜力&#xff0c;克服了变分自编码器中的后分布对齐障碍&#xff0c;缓解了生成对抗网络中的对抗性目标不稳定性…

深度挖掘响应式模式的潜力,从而精准优化AI与机器学习项目的运行效能,引领技术革新潮流

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 &#x1f525; 转载自热榜文章&#xff1a;探索设计模式的魅力&#xff1a;深度挖掘响应式模式的…

uni-starter的微信登录拿不到登录者的昵称,头像,手机号问题记录

uni-starter的微信登录竟然拿不到登录者的昵称&#xff0c;头像&#xff0c;手机号 获取手机号的方法在另外一篇文章中&#xff0c;需要认证&#xff0c;需要有营业执照 uni.login({"provider": type,"onlyAuthorize": true,// #ifdef APP"univerif…

RabbitMQ - Spring boot 整合 RabbitMQ

一、RabbitMQ 1、RabbitMQ 使用场景 1.1、服务解耦 假设有这样一个场景, 服务A产生数据, 而服务B,C,D需要这些数据, 那么我们可以在A服务中直接调用B,C,D服务,把数据传递到下游服务即可 但是,随着我们的应用规模不断扩大,会有更多的服务需要A的数据,如果有几十甚至几百个下…

Docker Desktop修改镜像存储路径 Docker Desktop Start ... 卡死

1、CMD执行wsl -l -v --all 2、Clean / Purge data 3、导出wsl子系统镜像: wsl --export docker-desktop D:\docker\wsl\distro\docker-desktop.tar wsl --export docker-desktop-data D:\docker\wsl\data\docker-desktop-data.tar4、删除现有的wsl子系统&#xff1a; wsl -…

智游剪辑网页版发布了!

你是否因为软件安装麻烦而不愿意尝试本软件&#xff1f;那么可以试试网页版&#xff01;只需要一个浏览器&#xff0c;就可以直接访问了&#xff0c;网页版免安装&#xff0c;无广告&#xff0c;大部分功能都可以免费使用&#xff01; 网页版地址&#xff1a;app.zyjj.cc 界面…

汇编基础-----通过x64dbg了解什么是堆栈

汇编基础-----通过x64dbg了解什么是堆栈 什么是堆栈 在汇编语言中&#xff0c;堆栈&#xff08;stack&#xff09;是一种用于存储临时数据和执行函数调用的内存结构。堆栈是一种后进先出&#xff08;Last-In-First-Out, LIFO&#xff09;的数据结构&#xff0c;通常用于保存函…

ssm042在线云音乐系统的设计与实现+jsp

在线云音乐系统的设计与实现 摘 要 随着移动互联网时代的发展&#xff0c;网络的使用越来越普及&#xff0c;用户在获取和存储信息方面也会有激动人心的时刻。音乐也将慢慢融入人们的生活中。影响和改变我们的生活。随着当今各种流行音乐的流行&#xff0c;人们在日常生活中经…

08_ADC轮询方式读取电压值/DMA方式多通道采集/DAC数模转换

ADC轮询方式读取电压值/DMA方式多通道采集/DAC数模转换 ADC轮询方式读取电压值DMA方式多通道采集DAC数模转换 ADC轮询方式读取电压值 while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */HAL_ADC_Start(&hadc1);//启动ADC装换HAL_ADC_PollForConversion(&hadc…

多维时序 | Matlab实现TCN-LSTM时间卷积长短期记忆神经网络多变量时间序列预测

多维时序 | Matlab实现TCN-LSTM时间卷积长短期记忆神经网络多变量时间序列预测 目录 多维时序 | Matlab实现TCN-LSTM时间卷积长短期记忆神经网络多变量时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.【Matlab实现TCN-LSTM时间卷积长短期记忆神经网络多变量…

【C++ 继承】关于多继承、菱形继承你了解多少?

文章目录 1. 为什么 C 有多继承&#xff0c;Java 没有多继承呢&#xff1f;2. 什么是菱形继承呢&#xff1f;3. 菱形继承产生数据冗余和二义性问题 1. 为什么 C 有多继承&#xff0c;Java 没有多继承呢&#xff1f; C 实现多继承是为了满足某些场景的需要&#xff0c;但是有多继…