C++ 优先级队列的vector实现

news2024/11/19 20:32:48

前段时间在研究Astar算法,里面涉及到几个重要的知识点,链表数据结构、优先队列数据结构,在以前的工作中没有接触到,学习后发现真是好东西,对C++的认知更深了一步,不废话了,下面正文:
      队列大家很熟悉,可以用vector数据结构存储,优先队列可能新手不怎么熟悉(老兵可以略过本文),先可以参考下面这个链接对优先队列进行初步熟悉:
1、c++ 优先队列(priority_queue)

问题:

1、上个参考链接中优先队列中用到的测试数据都是int类型,如果把优先队列中用自定义的类或者结构体进行替代可以吗,我们只需要按照结构体中的某个成员变量的值进行排序,按照最大或者最小放在第一个;
2、可以用vector进行替代queue包,并且实现优先队列功能吗?怎么写。
本文主要围绕这两个问题,给出了一个测试代码

测试自定义类说明

自定义了MyPoint结构体、Node类,分别如下

struct MyPoint
{
	int x = -1;
	int y = -1;
}
class Node
{
public:
	Node() {
	}
	//这个是测试的初始化
	Node(double Cost,MyPoint Pos)
	{
		m_estimatedCost = Cost;//估算成本(预计成本),以该值作为类优先队列的排序方式
		m_position = Pos;
	}
	~Node(){
	}

public:
	double m_estimatedCost = 0;//估算成本(预计成本)
	double m_nodeTotalCost = 1;//总成本
	//estimatedCost = nodeTotalCost + estimatedCost;
	// C            =         S     +        H;
	bool m_bObstacle= false;//记录该节点是否是障碍物
	Node* m_parent = NULL;//父节点,存储父节点的地址
	MyPoint m_position = {-1,-1};
};

问题1的解决方案,vector自定义类排序

第一个问题实质上可以理解对vector容器中的自定义类/结构体进行排序,常用解法有两个:

解决方案1,使用匿名函数进行排序

匿名函数也叫lambda表达式,其介绍如下文章:
C++ Lambda表达式详解

主函数实现代码如下

//输出容器的点
void printfNodeVec(std::vector<Node> NodeVec){
	for (int i = 0; i < NodeVec.size(); i++){
		printf("(%d,%d)->", NodeVec[i].m_position.x, NodeVec[i].m_position.y);
	}
	printf("\n");
	return;
}

int main()
{
	//4个测试数据,第一个值进行初始化要排序的成员变量
	//我的测试节点中,位置大小和真正对比的值大小一致,便于好看
	Node P1(1, { 1,1 });
	Node P2(3, { 3,3 });
	Node P3(6, { 6,6 });
	Node P4(4, { 4,4 });
	
	//添加到vector中
	std::vector<Node> NodeVec;
	NodeVec.push_back(P1);
	NodeVec.push_back(P2);
	NodeVec.push_back(P3);
	NodeVec.push_back(P4);
	printf("\n vector添加的方法============================================================\n");
	printfNodeVec(NodeVec);//把路径打印出来
	//使用匿名函数,对vector里自定义类按m_estimatedCost成员变量的值进行排序
	std::sort(NodeVec.begin(), NodeVec.end(), [&](Node node1, Node node2)
	{
		return node1.m_estimatedCost < node2.m_estimatedCost;
	});
	printf("\n 排序后============================================================\n");
	printfNodeVec(NodeVec);//把路径打印出来
	return 0;
}

运行结果如下
在这里插入图片描述

更换一下匿名函数中的符号,排序倒过来了,如下图:
在这里插入图片描述

解决方案2,在Node类中进行定义大于符号或小于符号

我们尝试一下把匿名函数删除掉,进行编译,让系统进行自动编译,代码如下:

int main()
{
	//4个测试数据,第一个值进行初始化要排序的成员变量
	//我的测试节点中,位置大小和真正对比的值大小一致,便于好看
	Node P1(1, { 1,1 });
	Node P2(3, { 3,3 });
	Node P3(6, { 6,6 });
	Node P4(4, { 4,4 });

	//添加到vector中
	std::vector<Node> NodeVec;
	NodeVec.push_back(P1);
	NodeVec.push_back(P2);
	NodeVec.push_back(P3);
	NodeVec.push_back(P4);
	printf("\n vector添加的方法============================================================\n");
	printfNodeVec(NodeVec);//把路径打印出来
	使用匿名函数,对vector里自定义类按m_estimatedCost成员变量的值进行排序
	//std::sort(NodeVec.begin(), NodeVec.end(), [&](Node node1, Node node2)
	//{
	//	return node1.m_estimatedCost > node2.m_estimatedCost;
	//});

	std::sort(NodeVec.begin(), NodeVec.end());//删除掉匿名函数,让系统自己排序

	printf("\n 排序后============================================================\n");
	printfNodeVec(NodeVec);//把路径打印出来
	return 0;
}

编译后有如下错误,通过错误可以判断,==符号和>符号没有找到
在这里插入图片描述

在这里插入图片描述

系统不知道怎么进行比较和排序,再具体点就是不知道用Node函数中哪个变量进行比较排序,这里只需要在Node类中进行定义比较运算符即可

	bool operator<(const Node dstNode)const
	{//定义它的小于符号
		return this->m_estimatedCost < dstNode.m_estimatedCost;
	}

	bool operator>(const Node dstNode)const
	{//定义它的大于符号
		return this->m_estimatedCost > dstNode.m_estimatedCost;
	}

	bool operator ==(Node n)
	{//重构等于等于操作符
		if (this->m_estimatedCost == n.m_estimatedCost&& this->m_nodeTotalCost == n.m_nodeTotalCost&& this->m_bObstacle == n.m_bObstacle)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

所以完整的Node类应该如此

class Node
{
public:
	Node() {
	}
	//这个是测试的初始化
	Node(double Cost,MyPoint Pos)
	{
		m_estimatedCost = Cost;//估算成本(预计成本),以该值作为类优先队列的排序方式
		m_position = Pos;
	}
	~Node(){
	}
	
	bool operator<(const Node dstNode)const
	{//定义它的小于符号
		return this->m_estimatedCost < dstNode.m_estimatedCost;
	}

	bool operator>(const Node dstNode)const
	{//定义它的大于符号
		return this->m_estimatedCost > dstNode.m_estimatedCost;
	}

	bool operator ==(Node n)
	{//重构等于等于操作符
		if (this->m_estimatedCost == n.m_estimatedCost&& this->m_nodeTotalCost == n.m_nodeTotalCost&& this->m_bObstacle == n.m_bObstacle)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

public:
	double m_estimatedCost = 0;//估算成本(预计成本)
	double m_nodeTotalCost = 1;//总成本
	//estimatedCost = nodeTotalCost + estimatedCost;
	// C            =         S     +        H;
	bool m_bObstacle= false;//记录该节点是否是障碍物
	Node* m_parent = NULL;//父节点,存储父节点的地址
	MyPoint m_position = {-1,-1};
};

再编译那个删除了匿名函数的的主函数,发现可以编译通过。运行后结果如下:

在这里插入图片描述
注意:operator 这种写法同样适用于结构体中重写结构体的比较方法

问题2的解决方案,用vector重写一个优先队列的数据结构

我们写一个Node的优先队列,里面可以装很多Node类
问题分析:我们首先定义一个优先队列数据结构类(PriorityQueue),然后定义一个成员变量vector< Node>结构;再定义其追加Node方式,排序方式、删除方式、获取优先队列中第一个元素方式等等,后面可以更具实际情况进行自定义添加。在追加一个元素或者删除一个元素后对vector< Node>进行一次排序就行

下面我的写的一个PriorityQueue类如下

class PriorityQueue
{
public:
	PriorityQueue();
	~PriorityQueue();
	std::vector<Node>nodes;
	int Length(){
		return nodes.size();
	}
	void Push(Node node){
		this->nodes.push_back(node);
		Sort_ToUp();//A星算法中,第一个Node应该是成本最低的Node, 所以一般的排序都是按照升序来
	}

	void Sort_ToUp(){//升序
		std::sort(nodes.begin(), nodes.end(), [&](Node node1, Node node2)
		{
			return node1.m_estimatedCost < node2.m_estimatedCost;
		});
	}

	void Sort_ToDown()
	{//降序
		std::sort(nodes.begin(), nodes.end(), [&](Node node1, Node node2)
		{
			return node1.m_estimatedCost > node2.m_estimatedCost;
		});
	}

	void Remove(Node node)
	{//根据位置定位元素,
		//1、定位要删除的Node ID
		auto key = std::find(nodes.begin(), nodes.end(), node);//这里有个排序,用的是
		if (key != nodes.end())
		{
			nodes.erase(key, key+1);//删除指定元素
			Sort_ToUp();//A星算法中,第一个Node应该是成本最低的Node,所以一般的排序都是按照升序来
		}
		else
		{
			printf("node:(%d,%d),Not in nodes!\n",node.m_position.x,node.m_position.y);
		}
	}

	Node First()
	{//获取第一个Node,A星算法中,第一个Node应该是成本最低的Node,所以一般的排序都是按照升序来
		if (this->nodes.size() > 0)
		{
			return this->nodes[0];
		}
		else
		{
			return Node();
		}
	}

	bool Contains(Node node)
	{//检查队列中是否有某个节点
		
		auto key = std::find(nodes.begin(), nodes.end(), node);
		if (key != nodes.end()){//在队列里面
			return true;
		}
		else{//不在队列里面
			return false;
		}
	}
};

由于在进行节点(Node)删除的时候进行过对比MyPoint结构体,所以MyPoint结构体中也需要定义==符号操作,更新后的MyPoint结构体如下:

struct MyPoint
{
	int x = -1;
	int y = -1;
	
	bool operator ==(MyPoint p2){//重构了等于等于符号
		if (this->x == p2.x &&this->y == p2.y){
			return true;
		}
		else{
			return false;
		}
	}

	bool operator !=(MyPoint p2){//重构了不等于符号
		if (this->x == p2.x &&this->y == p2.y){
			return false;
		}
		else{
			return true;
		}
	}
};

测试添加元素的主函数:

int main()
{
//我的测试节点中,位置大小和真正对比的值大小一致,便于好看
	Node P1(1, { 1,1 });
	Node P2(3, { 3,3 });
	Node P3(6, { 6,6 });
	Node P4(4, { 4,4 });
	//std::vector<Node> NodeVec;
	PriorityQueue Queue1;//创建优先队列,使用vector添加方式进行添加点
	Queue1.nodes.push_back(P1);
	Queue1.nodes.push_back(P2);
	Queue1.nodes.push_back(P3);
	Queue1.nodes.push_back(P4);
	printf("\n vector添加的方法============================================================\n");
	printfNodeVec(Queue1.nodes);//把路径打印出来
	printf("\n调用成员函数的添加方法============================================================\n");
	PriorityQueue Queue2;//创建优先队列2,使用成员函数方式添加元素
	Queue2.Push(P1);
	Queue2.Push(P2);
	Queue2.Push(P3);
	Queue2.Push(P4);
	printfNodeVec(Queue2.nodes);//把路径打印出来

	printf("\n对Queue1升序排序后============================================================\n");
	Queue1.Sort_ToUp();
	printfNodeVec(Queue1.nodes);//把路径打印出来
	printf("\n对Queue1降序排序后============================================================\n");
	Queue1.Sort_ToDown();
	printfNodeVec(Queue1.nodes);//把路径打印出来

	printf("\n对Queue1删除(6,6)============================================================\n");
	Queue1.Remove(P3);
	printfNodeVec(Queue1.nodes);//把路径打印出来

	printf("\n对Queue1删除(6,6)============================================================\n");
	Node P5(8, { 8,8 });
	Queue1.Remove(P5);
	printfNodeVec(Queue1.nodes);//把路径打印出来
return 0;
}

运行结果如下,可以实现优先队列中添加元素
在这里插入图片描述

2023年第一篇文章,以备查阅。辉 2023.1.13

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

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

相关文章

【正点原子FPGA连载】第十一章U-Boot使用实验 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

1&#xff09;实验平台&#xff1a;正点原子MPSoC开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id692450874670 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第十一章U-Boot使…

ESP32接入米家-小爱同学-IDF环境-巴法平台

0 引言 冬天床边没有开关&#xff0c;睡觉懒得关灯&#xff0c;想通过小爱同学控制灯的开关&#xff0c;但是不想换开关。 所以 想用ESP32接入米家&#xff0c;控制一个舵机实现开关控制。 文章目录0 引言1 MQTT协议2 ESP32 MQTT例程2.1 ESP-MQTT 库2.2.1 配置结构体 esp_mqt…

【Python基础】字符串基本操作(切片、格式化、编码)

文章目录一. 字符串1.1 字符串切片操作1.2 格式化字符串1.2.1 内容填充1.2.2 宽度精度1.3 编码解码一. 字符串 1.1 字符串切片操作 字符串是不可变类型 不具备增、删、改操作切片操作将产生新的对象&#xff0c;但如果是相同的字符串&#xff0c;对象不变。 操作格式&#xf…

③电子产品拆解分析-充电宝台灯

③电子产品拆解分析-充电宝台灯一、功能介绍二、电路分析以及器件作用1、TP4056锂电池充电电路分析2、锂电池保护电路分析3、台灯灯光控制电路一、功能介绍 ①可进行两档调光&#xff1b;②长按按键可显示电池电量&#xff1b;③可进行Macio USB安卓接口充电以及USB接口输出放…

【图文教程】云服务器上,Linux安装VSFTPD组件及遇到的问题

服务器做迁移&#xff0c;从AXX云迁移到Txx云上&#xff0c;迁移的话&#xff0c;需要把图片服务器也迁移过去。之前使用的是VSFTPD这次也还用这个吧。这里就记录下FTP服务器安装及遇到的问题。 1&#xff1a;安装VSFTP组件 使用yum命令安装。安装命令如下: yum -y install …

Ubuntu18.04 利用Systemback制作ISO系统镜像和还原

Ubuntu18.04 利用Systemback制作系统镜像和还原1、安装Systemback2、利用Systemback制作Live镜像3、 将大于4G的sblive文件转换成 ISO 文件&#xff08;Systemback的界面中的转换选项不可用的情况&#xff09;4、利用Systemback还原系统&#xff08;利用Systemback还原系统出现…

一文详解 Linux Crontab 调度任务

最近接到这样一个任务&#xff1a; 定期(每天、每月)向“特定服务器”传输“软件服务”的运营数据&#xff0c;因此这里涉及到一个定时任务&#xff0c;计划使用Python语言添加Crontab依赖写一个定时任务的脚本&#xff0c;实现每天、每月向服务器上传运营数据。 这篇文章是我在…

界面控件DevExpress WPF中文指南 - 用主题设计器的后台视图升级主题

DevExpress WPF拥有120个控件和库&#xff0c;将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序&#xff0c;这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。DevExpress WPF的Theme…

Chevereto v4 专业版搭建个人图床图文教程(博主自用)

Chevereto 是一个优秀的图床程序&#xff0c;有免费版和付费版之分&#xff0c;目前&#xff0c;Chevereto 已更新至 V4 版本&#xff0c;今天为大家分享一下使用 Chevereto v4 最新专业版搭建个人图床的过程。1. 准备工作PHP 版本要求 8.0 及以上&#xff0c;MySQL 版本支持 5…

.net5项目集成百度富文本编辑器umeditor最全教程(含源码)

目前百度的umeditor已经停止维护了&#xff0c;net版本的分支源码包也停留在了net farmework4左右的版本&#xff0c;对于想要集成这款富文本编辑器到net5平台&#xff0c;具有较大难度&#xff0c;主要体现在以下几个方面&#xff1a;umeditor源码需要改造&#xff0c;需要具有…

【每日随笔】北京 MBA 学校选择

文章目录一、第一梯队二、第二梯队三、第三梯队四、MBA 的全日制和非全日制区别一、第一梯队 第一梯队 MBA : 招人非常严格 , 本科学历背景 , 薪资 , 工作年限 , 管理年限 , 要求很高 ; 二、第二梯队 第二梯队 MBA : 对外经贸大学 MBA 推荐 对外贸易 相关行业 , 对英语要求较高…

Dubbo高级特性

dubbo-admin安装 ●dubbo-admin管理平台&#xff0c;是图形化的服务管理页面 ●从注册中心中获取到所有的提供者 /消费者进行配置管理 ●路由规则、动态配置、服务降级、访问控制、权重调整、负载均衡等管理功能 ●dubbo- admin是一个前后端分离的项目。前端使用vue&#xff0…

[NeurIPS 2022] 消除视觉Transformer与卷积神经网络在小数据集上的差距

本文简要介绍NeurIPS 2022录用的论文“Bridging the Gap Between Vision Transformers and Convolutional Neural Networks on Small Datasets”的主要工作。该论文旨在通过增强视觉Transformer中的归纳偏置来提升其在小数据集上从随机初始化开始训练的识别性能。本文通过多种操…

M1pro 下通过Docker 安装 Redis

Mac M1pro 下通过Docker 安装 Redis 1、Redis镜像拉取&#xff0c;最新版本的镜像 启动Docker&#xff0c;打开终端输入命令&#xff1a;docker pull redis:latest 耐心等待拉取完毕 2、查看本地镜像&#xff0c;Redis是否下载成功 命令&#xff1a;docker images 3、运行启…

又一重要进展发布!OpenMMLab算法仓支持昇腾AI训练加速

近日&#xff0c;上海人工智能实验室的浦视开源算法体系&#xff08;OpenMMLab&#xff09;团队基于昇腾AI发布了MMDeploy 0.10.0版本&#xff0c;该版本已支持OpenMMLab算法仓库在昇腾异构计算架构CANN上的推理部署。而在最新发布的MMCV 1.7.0和MMEngine 0.3.0版本中&#xff…

Vue3——第十二章(Props)

一、Props 声明 一个组件需要显式声明它所接受的 props&#xff0c;这样 Vue 才能知道外部传入的哪些是 props&#xff0c;哪些是透传 attribute在使用 <script setup> 的单文件组件中&#xff0c;props 可以使用 defineProps() 宏来声明&#xff1a; 在没有使用 <sc…

【寒假每日一题】DAY.5 调整奇数偶数顺序

题目内容&#xff1a; 调整数组使奇数全部都位于偶数前面。题目&#xff1a;输入一个整数数组&#xff0c;实现一个函数&#xff0c;来调整该数组中数字的顺序使得数组中所有的奇数位于数组的前半部分&#xff0c;所有偶数位于数组的后半部分。思路&#xff1a; 第一步&#xf…

【Java并发编程] 线程八锁问题

文章目录1.共享会出现什么问题2. 什么是临界区3. synchronized解决方案4 线程八锁1.共享会出现什么问题 首先&#xff0c;我们先了解对某一资源共享会出现什么问题&#xff0c;然后怎么解决这个问题。 两个线程对初始值为 0 的静态变量一个做自增&#xff0c;一个做自减&…

STM32单片机CAN总线汽车自动会车灯远近光切换

实践制作DIY- GC0121-汽车自动会车灯 一、功能说明&#xff1a; 基于51单片机设计-汽车自动会车灯 功能介绍&#xff1a; OLED主控板&#xff1a;STM32F103C系列最小系统OLED显示3个按键&#xff08;开关、自动/手动、近光/远光&#xff09;CAN通讯模块 光敏LED板&#xff1a…

房产管理系统架构分析

数图互通高校房产管理系统是基于公司自主研发的FMCenterV5.0平台&#xff0c;是针对中国高校房产的管理特点和管理要求&#xff0c;研发的一套标准产品&#xff1b;通过在中国100多所高校的成功实施和迭代&#xff0c;形成了一套成熟、完善、全生命周期的房屋资源管理解决方案。…