《算法九》(A星寻路算法)

A星寻路:
  结构:N叉树
  直线代价斜线代价:符合勾股定理
  代价:每走一步,距离终点所付出的
  计算公式:f = g + h + w;
  f : 当前点到终点的代价
  g : 起点到当前点的代价
  h : 当前点到终点的预估代价(只计算直线距离,并忽略障碍)
  w : 权重 路: 平地 上坡路 丘陵 沼泽 坑

 

代码演示:

#include <string.h>>
#include <iostream>
#include <vector>
#include <windows.h>
using namespace std;

//代价  : 每走一步   距离终点所付出的

// f = g + h + w;
// f : 当前点到终点的代价
// g : 起点到当前点的代价
// h : 当前点到终点的预估代价(只计算直线距离,并忽略障碍)
// w : 权重  路:   平地    上坡路  丘陵  沼泽   坑 


//直线代价斜线代价:符合勾股定理 
//直线代价
#define ZXDJ  10
//斜线代价
#define XXDJ  14


//地图高  Y   竖着  行数  列  
#define ROWS  12
//地图宽  X   横着  列数  行
#define COLS  12



struct MyPoint{
	int row;//x 
	int col;//y 
	//f = g+h 
	int h;		//当前点到终点预估代价
	int f;		//当前点的代价
	int g;		//起点到当前点的代价

	void setF(){ f = g + h; }
};

//辅助地图 
struct pathNode{
	int		val;//值 
	bool	isFind;//有没有走过 
};

//方向枚举 :上下左右/左上左下右上右下 
enum direct{p_up,p_down,p_left,p_right,lup,ldown,rup,rdown};


//树节点类型
struct treeNode{
	MyPoint				pos;
	treeNode*			pParent;
	vector<treeNode*>	child;
};
//创建一个树节点并返回节点首地址
//treeNode* CreateNode(const MyPoint& point);
treeNode* CreateNode(int row,int col);

//判断pos点能不能走,能走返回true,否则返回false
bool canWalk(pathNode pathMap[ROWS][COLS], MyPoint pos);

//计算h值并返回
int getH(const MyPoint& currentPos, const MyPoint& endPos);

int main()
{
	int map[ROWS][COLS] = {
		{ 0, 1, 1, 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, 1, 1, 0, 0, 0, 0, 0, 0 },
		{ 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0 },
		{ 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 },
		{ 0, 0, 1, 1, 1, 1, 0, 0, 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, 0, 0, 0, 0, 1, 0, 0, 0, 0, 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, 1, 0, 0, 0, 0, 0, 0 }
	};

	pathNode pathMap[ROWS][COLS] = { 0 };
	for (int i = 0; i < ROWS; i++){
		for (int j = 0; j < COLS; j++){
			pathMap[i][j].val = map[i][j];
		}
	}
	MyPoint begPos = { 1, 1 };
	MyPoint endPos = { 4, 9 };
	//准备树结构
	treeNode* pRoot = NULL;
	//起点成为树根节点
	pRoot = CreateNode(begPos.row, begPos.col);
	//标记起点走过
	pathMap[begPos.row][begPos.col].isFind = true;


	//临时指针 指向当前节点
	treeNode* pTemp = pRoot;
	//临时指针 暂时保存当前点的孩子
	treeNode* pTempChild = NULL;
	//保存当前备选点的数组
	vector<treeNode*> buff;
	
	//准备两个迭代器

	//遍历整个容器
	vector<treeNode*>::iterator it;
	//定位容器中f值最小的元素
	vector<treeNode*>::iterator itMin;
	//临时点类型
	MyPoint tempPos;
	bool isFindEnd = false;
	
	
	//寻路
	while (1){
		
		//1 一个点压出八个点
		for (int i = 0; i < 8; i++){
			tempPos = pTemp->pos;
			//1.1 每个点做个临时的出来
			switch (i)
			{
			//上下左右   左上左下右上右下
			//同时需要改变g值 
			case p_up:tempPos.row--;tempPos.g += ZXDJ;break;
			case p_down:tempPos.row++;tempPos.g += ZXDJ;break;
			case p_left:tempPos.col--;tempPos.g += ZXDJ;break;
			case p_right:tempPos.col++;tempPos.g += ZXDJ;break;
			case lup:tempPos.row--;tempPos.col--;tempPos.g += XXDJ;break;
			case ldown:tempPos.row++;tempPos.col--;tempPos.g += XXDJ;break;
			case rup:tempPos.row--;tempPos.col++;tempPos.g += XXDJ;break;
			case rdown:tempPos.row++;tempPos.col++;tempPos.g += XXDJ;break;
			}
			//1.2 这个点可以走
			if (canWalk(pathMap, tempPos)){
				//1.2.1 创建树节点
				pTempChild = CreateNode(tempPos.row, tempPos.col);
				//1.2.2 计算节点的g值 h值 f值:f=g+h
				pTempChild->pos.g = tempPos.g;
				pTempChild->pos.h = getH(pTempChild->pos, endPos);//计算h值:到终点预估代价 
				pTempChild->pos.setF();//计算f 
				
				printf("(%d,%d) ",
					pTempChild->pos.row, pTempChild->pos.col);

				//1.2.3 新结点入树
				pTemp->child.push_back(pTempChild);
				pTempChild->pParent = pTemp;
				//1.2.4 新节点保存到数组中
				buff.push_back(pTempChild);
			}
			
		}
		printf("\n");
		
		//2 遍历buff数组,找出其中f值最小的一个
		itMin = buff.begin();
		for (it = buff.begin(); it != buff.end(); it++){
			itMin = ((*itMin)->pos.f > (*it)->pos.f) ? it : itMin;
		}

		//3 当前点变成这个点
		pTemp = *itMin;
		//标记当前点走过
		pathMap[pTemp->pos.row][pTemp->pos.col].isFind = true;
		
		//4 buff数组中删除这个点
		buff.erase(itMin);
		
		//5 判断是否找到终点
		if (pTemp->pos.row == endPos.row &&
			pTemp->pos.col == endPos.col){
			isFindEnd = true;
			break;
		}
		
		//6 判断地图是否没有出口
		if (0 == buff.size()) break;
	}
	
	

	
	// 打印路径
	if (isFindEnd){
		printf("找到终点啦!\n");
		printf("打印路径:终点-->起点\n");
		printf("\n");
		printf("\n");
		while (pTemp){
			printf("(%d,%d) ", pTemp->pos.row, pTemp->pos.col);
			pTemp = pTemp->pParent;
		}
		printf("\n");
	}
	return 0;
}

treeNode* CreateNode(int row, int col){
	treeNode* pNew = new treeNode;
	memset(pNew, 0, sizeof(treeNode));
	pNew->pos.row = row;
	pNew->pos.col = col;
	return pNew;
}


//判断pos点能不能走,能走返回true,否则返回false
bool canWalk(pathNode pathMap[ROWS][COLS], MyPoint pos){
	//不在地图范围内
	if (pos.row >= ROWS || pos.row < 0 || pos.col >= COLS || pos.col < 0)
		return false;
	//是障碍
	if (pathMap[pos.row][pos.col].val) return false;
	//走过
	if (pathMap[pos.row][pos.col].isFind) return false;
	return true;
}


//计算h值并返回
int getH(const MyPoint& currentPos, const MyPoint& endPos){
	int x = (currentPos.col > endPos.col) ? (currentPos.col - endPos.col) : (endPos.col - currentPos.col);
	int y = (currentPos.row > endPos.row) ? (currentPos.row - endPos.row) : (endPos.row - currentPos.row);
	return (x+y)*ZXDJ;
}

 

版权声明:本文为Whgy原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/Whgy/p/12294978.html