A*寻路算法

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

A*寻路算法

概念
思路
过程
完整代码
三种算法的差别及应用场景


概念

通过计算和量化行走的各个方向的代价,来选择最优路径
代价公式:
f = g+h;
f:最终代价
g:当前代价
h:预估代价(有两种计算方法:欧拉距离和曼哈顿距离)
欧拉距离:(begin.x-end.x)^2 + (begin.y-end.y) ^2 然后开方
曼哈顿距离:x = |begin.x-end.x|; y = |begin.y -end.y|,然后x+y

思路

建立一颗树,树里面有坐标和代价值以及父节点和子节点,通过遍历8个方向算出代价,比较代价值选择方向,将结点放入树中,然后建立一个容器放每次选择方向的结点,并将当前结点进行标记走过(不标记的话会进入死循环),如果遇到死路就删除当前结点退回到代价最小的结点(这里删除的结点都是容器里的哈),直到找到终点或者容器为空结束(说明全是死路)。

过程

第一步在这里插入图片描述
第二步
在这里插入图片描述
之后以此类推,直到寻找到目的地或者没路可以走。

完整代码

#include "num_type.h"
using namespace NUM_TYPE;

const int ROW = 10;
const int COL = 10;
const int ZXDJ = 10;	//直线代价
const int XXDJ = 14;	//斜线代价
enum Dir{p_up,p_down,p_left,p_right,p_lup,p_ldown,p_rup,p_rdown};
struct Mypoint
{
	int row;
	int col;
	int f, g, h;//f:总代价,g:当前代价,h:预估代价
	bool operator==(const Mypoint& pos)
	{
		return (pos.row == row && pos.col == col);
	}
	void GetH(const Mypoint& Begpos, const Mypoint& Endpos);//算代价
	void GetF()
	{
		f = g + h;
	}
};

//树结构存储节点
struct TreeNode
{
	Mypoint pos;
	TreeNode* pParent;
	vector<TreeNode*> pChild;	//存储多个孩子节点的容器
	//构造函数
	TreeNode(const Mypoint& pos)
	{
		this->pos = pos;
		pParent = nullptr;
	}
};

BOOL CanWalk(INUM map[ROW][COL], BOOL pathMap[ROW][COL], const Mypoint& pos);
int main()
{
	INUM map[ROW][COL] =
	{
		{0,0,0,0,1,0,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0},
		{0,0,0,1,1,0,1,0,0,0},
		{0,0,0,0,1,0,1,0,0,0},
		{0,0,0,0,1,0,1,0,0,0},
		{0,0,1,0,1,0,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0},
		{0,0,0,0,0,0,1,0,0,0},
		{0,0,0,0,1,1,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0},
	};

	//起始点和终点
	Mypoint Begpos = { 1,1 };
	Mypoint Endpos = { 6,5 };
	//辅助地图
	BOOL pathMap[ROW][COL] = { false };

	//创建树根
	TreeNode* pRoot = new TreeNode(Begpos);

	vector<TreeNode*> buff;	//存储数组
	vector<TreeNode*>::iterator itMin;//数组的迭代器

	TreeNode* pCurrent = pRoot;	//记录当前节点
	TreeNode* pTemp = nullptr;	//试探节点

	BOOL isFindEnd = false;
	//开始寻路,
	while (1)
	{
		//1. 某个点八个方向依次遍历 计算g代价
		for (int i = 0; i < 8; ++i)
		{
			//new一个新的结点
			pTemp = new TreeNode(pCurrent->pos);
			switch (i)
			{
			case p_up:
				pTemp->pos.row--;
				pTemp->pos.g += ZXDJ;
				break;
			case p_down:
				pTemp->pos.row++;
				pTemp->pos.g += ZXDJ;
				break;
			case p_left:
				pTemp->pos.col--;
				pTemp->pos.g += ZXDJ;
				break;
			case p_right:
				pTemp->pos.col++;
				pTemp->pos.g += ZXDJ;
				break;
			case p_lup:
				pTemp->pos.row--;
				pTemp->pos.col--;
				pTemp->pos.g += XXDJ;
				break;
			case p_ldown:
				pTemp->pos.row++;
				pTemp->pos.col--;
				pTemp->pos.g += XXDJ;
				break;
			case p_rup:
				pTemp->pos.row--;
				pTemp->pos.col++;
				pTemp->pos.g += XXDJ;
				break;
			case p_rdown:
				pTemp->pos.row++;
				pTemp->pos.col++;
				pTemp->pos.g += XXDJ;
				break;
			}
			//判断他们能不能走,能走的计算h及f 入树  存储在buff数组
			if (CanWalk(map, pathMap, pTemp->pos))
			{	//能走
				//计算代价
				pTemp->pos.GetH(Begpos, Endpos);
				pTemp->pos.GetF();
				//放入树中
				pCurrent->pChild.push_back(pTemp);
				pTemp->pParent = pCurrent;
				//存入数组
				buff.push_back(pTemp);
				//标记走过这个点
				pathMap[pTemp->pos.row][pTemp->pos.col] = true;
			}
			else
			{
				//不能走则直接删除这个节点
				delete pTemp;
				pTemp = nullptr;
			}
		}
		// 找出数组中存储的最小代价的节点并删除
		itMin = buff.begin();	//找最小
		for (auto it = buff.begin(); it != buff.end(); ++it)
		{
			itMin = ((*itMin)->pos.f < (*it)->pos.f) ? itMin : it;
		}
		//移动
		pCurrent = *itMin;
		//删除最小代价节点
		buff.erase(itMin);
		
		//有没有到达终点
		if (pCurrent->pos == Endpos)
		{
			isFindEnd = true;
			break;
		}
		//没有终点,自然一直删除节点,则buff为空
		if (buff.size() == 0)
		{
			break;
		}
	}

	if (isFindEnd)
	{
		cout << "找到终点了!\n";
		while (pCurrent)
		{
			cout << "(" << pCurrent->pos.row << "," << pCurrent->pos.col << ")";
			pCurrent = pCurrent->pParent;
		}
	}
	else
	{
		cout << "没有找到终点!\n";

	}
	return 0;
}

BOOL CanWalk(INUM map[ROW][COL], BOOL pathMap[ROW][COL], const Mypoint& pos)
{
	//如果越界
	if (pos.row < 0 || pos.col < 0 || pos.row >= ROW || pos.col >= COL)
	{
		return false;
	}
	//如果是墙
	if (map[pos.row][pos.col])
	{
		return false;
	}
	//如果已经走过
	if (pathMap[pos.row][pos.col])
	{
		return false;
	}
	return true;
}

void Mypoint::GetH(const Mypoint& Begpos, const Mypoint& Endpos)
{
	int temp_x = (Endpos.col > Begpos.col) ? (Endpos.col - Begpos.col) : (Begpos.col - Endpos.col);
	 int temp_y = (Endpos.row > Begpos.row) ? (Endpos.row - Begpos.row) : (Begpos.row - Endpos.row);
	h = temp_x + temp_y;
	return;
}

三种算法的差别及应用场景

深度寻路算法:是一种盲目式搜索,选择一个方向一直往下走,直到找到终点或者遇到死路返回(栈).
广度寻路算法:是一种盲目式搜索,一层一层的去遍历,只到找到终点或者遍历完(队列)。
A*寻路算法:是一种启发式搜索,根据代价进行寻找(二叉堆)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值