STL —— priority_queue

图片名称

博主首页: 有趣的中国人
 

专栏首页: 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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024年管理、经济发展与商务分析国际会议(ICMEDBA2024)

2024年管理、经济发展与商务分析国际会议&#xff08;ICMEDBA2024&#xff09; 会议简介 2024年管理、经济发展和商业分析国际会议&#xff08;ICMEDBA2024&#xff09;将在中国昆明举行。会议聚焦管理、经济发展和商业分析研究领域&#xff0c;旨在为相关领域的专家、学者、…

保障通信安全的端到端加密技术

随着互联网技术的飞速发展&#xff0c;人们的通信方式也变得日益多样化和便捷化。然而&#xff0c;通信的便捷性背后也隐藏着信息安全的风险。在这样的背景下&#xff0c;端到端加密技术应运而生&#xff0c;成为了保障通信安全的重要手段。本文将对端到端加密技术进行详细介绍…

RocketMQ 02 功能大纲介绍

RocketMQ 02 主流的MQ有很多&#xff0c;比如ActiveMQ、RabbitMQ、RocketMQ、Kafka、ZeroMQ等。 之前阿里巴巴也是使用ActiveMQ&#xff0c;随着业务发展&#xff0c;ActiveMQ IO 模块出现瓶颈&#xff0c;后来阿里巴巴 通过一系列优化但是还是不能很好的解决&#xff0c;之后…

CodeMaid:Visual Studio代码自动整理插件!

推荐一款Visual Studio的扩展插件&#xff0c;可以帮助开发者更高效地管理和维护代码。 01 插件简介 CodeMaid是一款Visual Studio的扩展插件&#xff0c;其主要功能包括代码整理、代码格式化、自动注释、快速导航等&#xff0c;这些功能都可以提高开发者的编程效率和代码质量…

性能测试-数据库优化二(SQL的优化、数据库拆表、分表分区,读写分离、redis、数据库监控)

数据库优化 explain select 重点&#xff1a; type类型&#xff0c;rows行数&#xff0c;extra SQL的优化 在写on语句时&#xff0c;将数据量小的表放左边&#xff0c;大表写右边where后面的条件尽可能用索引字段&#xff0c;复合索引时&#xff0c;最好按复合索引顺序写wh…

5V_6A/4A高性能低EMI同步降压整流器内置8 mΩ NMOS, 31 mΩ PMOS

概述 PCD1500 是一个非常小、高效、低噪音同步 6A 降压直流/直流变换器&#xff0c;从 2.5V 到 5.5V 的输入电源运行。该变换器使用固定开关频率&#xff0c;在 1MHz 到 10MHz 时进行峰值电流模式控制&#xff0c;最小开关时间低至 22ns&#xff0c;通过较小的外部组件实现快速…

第 6 章 URDF、Gazebo与Rviz综合应用(自学二刷笔记)

重要参考&#xff1a; 课程链接:https://www.bilibili.com/video/BV1Ci4y1L7ZZ 讲义链接:Introduction Autolabor-ROS机器人入门课程《ROS理论与实践》零基础教程 6.7.4 kinect信息仿真以及显示 通过 Gazebo 模拟kinect摄像头&#xff0c;并在 Rviz 中显示kinect摄像头数据…

【Linux系统编程】第三弹---基本指令(一)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、touch指令 2、mkdir指令 3、ls 指令 4、pwd命令 3、cd 指令 6、rmdir指令 && rm 指令 7、man指令 7、cp指令 …

南京观海微电子---外电路和内电路的区别和联系、应用和优缺点

什么是外电路和内电路 首先&#xff0c;我们要明白什么是电路。电路是指由导体或其他元件连接起来的闭合路径&#xff0c;能够让电流通过。我们平时见到的灯泡、手机、电脑等都是由不同的电路组成的。 电路一点通 “电路一点通”聚电路技术资源、电子电路、高品质电路图、电路…

【计算机毕业设计】4S店车辆管理系统——后附源码

&#x1f389;**欢迎来到我的技术世界&#xff01;**&#x1f389; &#x1f4d8; 博主小档案&#xff1a; 一名来自世界500强的资深程序媛&#xff0c;毕业于国内知名985高校。 &#x1f527; 技术专长&#xff1a; 在深度学习任务中展现出卓越的能力&#xff0c;包括但不限于…

vue+springboot实现聊天功能

前言 在我的项目中&#xff0c;突然有种想法&#xff0c;想实现聊天功能&#xff0c;历经一段时间终于做出来了&#xff1b;那么接下来会讲解如何实现&#xff0c;这篇文章只会实现最基础的逻辑&#xff0c;实时获取对方聊天记录&#xff0c;话不多说&#xff0c;我们就开始吧…

脚本开发与自动化运维

shell脚本开发 grep搜索工具 参数&#xff1a; -A<显示行数>&#xff1a;-A NUM, --after-context NUM&#xff0c;除了显示符合范本样式的那一行之 外&#xff0c;并显示该行之后的内容。 -B<显示行数>&#xff1a;--before-context NUM&#xff0c;除了显示…

nmap、john、tcpdump

Kali是基于Debian的Linux发行版&#xff0c;Kali Linux包含上百个安全相关工具&#xff0c;如渗透测试、安全检测、密码安全、反向工程等。 扫描&#xff1a;获取一些公开、非公开信息为目的&#xff1b;检查潜在的风险、查找可攻击的目标、收集设备/主机/系统/软件信息、发现可…

开源模型应用落地-chatglm3-6b-批量推理-入门篇(四)

一、前言 刚开始接触AI时&#xff0c;您可能会感到困惑&#xff0c;因为面对众多开源模型的选择&#xff0c;不知道应该选择哪个模型&#xff0c;也不知道如何调用最基本的模型。但是不用担心&#xff0c;我将陪伴您一起逐步入门&#xff0c;解决这些问题。 在信息时代&#xf…

从AdTech转战Martech,驰骛科技的PaaS之路

中国最早的Adtech公司之一&#xff0c;在被全资收购后&#xff0c;其创始团队又创立了一家Martech公司。赛道的变更也从侧面反映出中国营销技术市场的发展轨迹。 驰骛科技创始团队来自易传媒核心团队&#xff0c;驰骛科技创始人程华奕是易传媒创始人兼CTO&#xff0c;是中国最早…

修改taro-ui-vue3的tabs组件源码增加数字标签

需求&#xff1a;taro-ui-vue3的tabs组件上增加数字标记 步骤一&#xff1a;node_modules文件夹下找到taro-ui-vue3/lib/tabs/index.js 把173行的这一段替换成下面这段&#xff0c;然后写上样式 default: () > item.number ? [h(View, {class: at-tabs__item_in}, {defau…

maven3.9的settings.xml 内容学习

settings.xml 文件介绍 settings.xml 是 Maven 的配置文件&#xff0c;它允许你自定义 Maven 的行为&#xff0c;比如设置仓库、代理、认证信息等。在 Maven 3.9 中&#xff0c;settings.xml 的结构和内容可能与之前的版本相似&#xff0c;但可能会有一些小的改进或变化。下面…

经典文献阅读之--RaLF(激光雷达地图中基于流的全局和度量雷达定位)

0. 简介 激光雷达地图中基于流的全局和度量雷达定位。自主机器人的定位是至关重要的。尽管基于相机和激光雷达的方法已经得到大量研究&#xff0c;但是它们会受到恶劣的光照和天气条件的影响。因此&#xff0c;最近雷达传感器由于其对这种条件固有的鲁棒性而受到关注。在《RaL…

回归预测 | Matlab实现SSA-GRNN麻雀算法优化广义回归神经网络多变量回归预测(含优化前后预测可视化)

回归预测 | Matlab实现SSA-GRNN麻雀算法优化广义回归神经网络多变量回归预测(含优化前后预测可视化) 目录 回归预测 | Matlab实现SSA-GRNN麻雀算法优化广义回归神经网络多变量回归预测(含优化前后预测可视化)预测效果基本介绍程序设计参考资料预测效果

linux应急响应基础命令

一、cpu使用率-top top -c -o %CPU -c 显示进程的命令行参数 -o 按照CPU占用从大到小排序二、用户信息 1、查看系统所有用户信息 [rootcentos7 ~]# cat /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nol…