A星寻路算法学习(附自己写的源码)

A星寻路算法

我们在知道了广度寻路算法(循环嵌套开销大)和深度寻路算法(不一定能找到最佳路径)的优缺点后,我们开始学习A星寻路算法

A星寻路算法:他的优点是能找到最短路径,不需要回退,没有广度寻路算法那么大的开销

而他的核心逻辑就是:量化评估

量化评估这点很重要,简单来说就是代价,万事万物都有代价,而量化评估就是由你来决定这个代价的值(这个值不能离谱,需要合乎实际)。

如,用数字表示,不能太离谱了

现在假设代价是:        直线走1格代价10       ->5

                                      斜线走1格代价14     ->7

为什么是这个数呢,原因是:

红色的为出发点,则要到右上角这个点,走的斜线和走右边的直线一画,一个等腰直角三角形就出现了。

那么他们的比例要符合直角边与斜边的比例,即1:1.414(根号二)

如果这个代价设定是不合理的,得到的结果就会和想要得到的结果背道而驰。

代价的设置是十分重要

最后就是F=g+h       

F:最终用来评估的代价

G:起点到当前点,已经付出的代价

                g是会随着移动而增加

H:当前点到终点预估代价

                h的计算:无视障碍到终点距离,是会随着移动而改变(离终点越近,这个越小)

算出来之后,哪个f的值最小就是最佳路径

相对的细节也需要完善,要准备一个数组存储这些f,当其走过则删除(必然是删除最小的)【假如这个时候最小的路程会遇到墙壁,因为已经删除了,所以会选择另一个最小代价的去】

然后从数组里面查找另一个最小的,然后就可以从这个最小的开始继续寻路

以下是源码(内涵注释):

#include <iostream>
#include<vector>
using namespace std;

#define ROW 10
#define COL 10

enum Direction
{
	p_up,
	p_down,
	p_left,
	p_right,
	p_leftDown,
	p_rightDown,
	p_leftUp,
	p_rightUp,
};

#define ZXprice 10	//直线代价
#define XXprice 14	//斜线代价

struct myPoint
{
	int row, col;
	int f, g, h;

	void getH(int r, int c);
	void getF()
	{
		f = g + h;
	}
	bool operator==(const myPoint& p)
	{
		return (row == p.row && col == p.col);
	}

};

//做树
struct TreeNode
{
	myPoint				pos;
	TreeNode*			pParent;
	vector<TreeNode*>	pChild;

	TreeNode(const myPoint& p)
	{
		pos = p;
		pParent = NULL;
	}
};

//能不能走
bool canWork(int map[ROW][COL],bool pathMap[ROW][COL], myPoint pos)
{
	//是否越界
	if (pos.row<0||pos.row>=ROW||pos.col<0||pos.col>=COL)
	{
		return false;
	}
	//是否是墙
	else if (1 == map[pos.row][pos.col])
	{
		return false;
	}
	//是否走过
	else if (pathMap[pos.row][pos.col] == true)
	{
		return false;
	}
	return true;
}
int main()
{
	int map[ROW][COL] = {
		{0,0,0,0,1,1,1,0,0,0},
		{0,0,0,0,1,0,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0},
		{0,0,0,0,0,0,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0},
		{0,0,0,0,0,0,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0},
		{0,0,0,0,1,0,0,0,0,0},
	};
	bool pathMap[ROW][COL] = { 0 };
	myPoint beginPos = { 2,1 };//起点设置
	myPoint endPos = { 9,9 };//终点设置

	pathMap[beginPos.row][beginPos.col] = true;//走过起点

	//创建树的根节点
	TreeNode* pRoot = new TreeNode(beginPos);

	vector<TreeNode*> buff;//数组存储
	//迭代器
	vector<TreeNode*>::iterator it;
	vector<TreeNode*>::iterator MinIt;
	
	TreeNode* pCurrent = pRoot;
	TreeNode* pChild = NULL;
	bool isFindEnd = false;
	while (1)//循环寻路
	{
		//1.寻找当前点周围能走的点
		for (int i = 0; i < 8; i++)
		{
			pChild = new TreeNode(pCurrent->pos);
			switch (i)
			{
			case p_up:pChild->pos.row--; pChild->pos.g += ZXprice; break;
			case p_down:pChild->pos.row++; pChild->pos.g += ZXprice; break;
			case p_left:pChild->pos.col--; pChild->pos.g += ZXprice; break;
			case p_right:pChild->pos.col++; pChild->pos.g += ZXprice; break;
			case p_leftUp:pChild->pos.row--; pChild->pos.col--; pChild->pos.g += XXprice; break;
			case p_rightUp:pChild->pos.row--; pChild->pos.col++; pChild->pos.g += XXprice; break;
			case p_leftDown:pChild->pos.row++; pChild->pos.col--; pChild->pos.g += XXprice; break;
			case p_rightDown:pChild->pos.row++; pChild->pos.col++; pChild->pos.g += XXprice; break;
			}
			//2.计算f的值并入树,buff存储
			//1..先判断能不能走
			if (canWork(map, pathMap, pChild->pos))//能走
			{
				//计算f的值
				pChild->pos.getH(endPos.row, endPos.col);
				pChild->pos.getF();
				//入树
				pCurrent->pChild.push_back(pChild);
				pChild->pParent = pCurrent;
				//buff存储
				buff.push_back(pChild);
				//标记走过的路
				pathMap[pChild->pos.row][pChild->pos.col] = true;
			}
			else//不能走
			{
				delete pChild;
				pChild = NULL;
			}
		}
		
		//3.当前点周围都找完了,找出buff中f值最小的点,下次循环就是当前点
		MinIt = buff.begin();//假设第一个最小
		for ( it = buff.begin(); it != buff.end(); it++)
		{
			MinIt = (((*it)->pos.f < (*MinIt)->pos.f) ? it : MinIt);
		}
		pCurrent = *MinIt;
	
		//4.buff数组中删除最小f
		buff.erase(MinIt);
		//5.判断是否找到终点了
		if (pCurrent->pos==endPos)
		{
			isFindEnd = true;
			break;
		}
		//如果地图找完了,没有找到终点
		if (buff.size()==0)//记录数组里面的全部走完了
		{
			break;
		}
	}
	//找到终点即打印
	if (isFindEnd)
	{
		cout << "找到终点";
		//对结果进行打印
		while (pCurrent)//通过现在的结尾一路上走
		{
			cout <<"(" << pCurrent->pos.row << "," << pCurrent->pos.col << ")";
			pCurrent = pCurrent->pParent;
		}
	}
	else
	{
		cout << "找不到终点";
	}
	return 0;
}

void myPoint::getH(int r, int c)
{
	int x = ((c > col) ? (c - col) : (col - c));
	int y = ((r > row) ? (r - row) : (row - r));

	h = (x + y) * ZXprice;	//有了h,即有了F
}

猜你喜欢

转载自blog.csdn.net/q244645787/article/details/128321208