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

48 篇文章 2 订阅
13 篇文章 1 订阅

前段时间在研究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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值