A*算法C实现

参考 http://www.cppblog.com/christanxw/archive/2006/04/07/5126.html 实现了A*算法,模拟了一下,大多数场景还是可以应对的,以传统的场景为例 

 

以下,1为源,2为目的,-1为墙。

 

初始地图:

 0  0  0  0  0
 0  0 -1  0  0
 0  1 -1  0  2
 0  0 -1  0  0
 0  0  0  0  0

路径:

 0  0  0  0  0
 0  0 -1  0  0
 0  1 -1  0  2
 0  1 -1  1  0
 0  0  1  0  0

 

但对于下面的地址,处理的结果很差

 0  0  0  0  0
 0 -1  0 -1  0
 1 -1  0 -1  2
 0 -1  0 -1  0
 0  0  0  0  0

 

路径: 

 0  1  0  0  0
 1 -1  1 -1  0
 1 -1  1 -1  2
 0 -1  1 -1  1
 0  0  0  1  0

 

这种场景还要再研究下优化方法,第一版的草稿先粘一下,有兴趣的朋友可以参考。为了方便大家编译,把地图编辑器也去掉了,换成硬编码的二维数组。

 

/*
 * A* 算法模拟
 */

#include <stdio.h>
#include <stdlib.h>
#include <vector>

using std::vector;

typedef struct stNode
{
	stNode() : x(0), y(0), px(0), py(0), f(0), g(0), h(0)
	{}

	int x;
	int y;
	int px; /* 父结点横坐标 */
	int py; /* 父结点纵坐标 */
	int f;
	int g;
	int h;
}Node;

/*
 * 地图0为通路,1为起点,2为终点,-1为不可达
 */
#define ROW 5
#define COLUMN 5
int short_map[][COLUMN] = {
	{0, 0, 0, 0, 0},
	{0, -1, 0, -1, 0},
	{1, -1, 0, -1, 2},
	{0, -1, 0, -1, 0},
	{0, 0, 0, 0, 0}};

vector<Node> close_map;
vector<Node> open_map;

/*
 * 找到本次查找的边界
 */
void CalcBound(Node & cur, int &startx, int &starty, int &endx, int &endy)
{
	startx = (cur.x > 0) ? (cur.x - 1) : cur.x;
	starty = (cur.y > 0) ? (cur.y - 1) : cur.y;
	endx = (cur.x < COLUMN) ? (cur.x + 1) : cur.x;
	endy = (cur.y < COLUMN) ? (cur.y + 1) : cur.y;
}

/*
 * 计算G值,G=从起点 A 移动到指定方格的移动代价,沿着到达该方格而生成的路径 
 */
int CalcG(Node cur, int nextx, int nexty)
{
	if (cur.x == nextx || cur.y == nexty)
	{
		return 10;	
	}
	else
	{
		return 14;
	}
}

/*
 * 计算H值,H=从指定的方格移动到终点 B 的估算成本
 * 我们使用 Manhattan 方法,计算从当前方格横向或纵向移动到达目标所经过的方格数,忽略对角移动,然后把总数乘以 10 
 *
 */
int CalcH(Node dst, int nextx, int nexty)
{
	int stepnum = 0;

	stepnum += ((dst.x >= nextx) ? 1 : -1) * (dst.x - nextx);
	stepnum += ((dst.y >= nexty) ? 1 : -1) * (dst.y - nexty);

	return stepnum * 10;
}

Node * IsInCloseMap(int i, int j)
{
	int pos = 0;
	for (vector<Node>::const_iterator it = close_map.begin(); it != close_map.end(); it++, pos++)
	{
		if (it->x == i && it->y == j )
		{
			return &close_map[pos];
		}
	}

	return NULL;
}

Node * IsInOpenMap(int i, int j)
{
	int pos = 0;
	for (vector<Node>::const_iterator it = open_map.begin(); it != open_map.end(); it++, pos++)
	{
		if (it->x == i && it->y == j )
		{
			return &(open_map[pos]);
		}
	}

	return NULL;
}

void InsertCloseList(Node & node)
{
	close_map.push_back(node);
}

void InsertOpenList(Node & node)
{
	open_map.push_back(node);
}

/*
 * 计算F值,返回下一步坐票
 *
 * param int cur: 当前计算的坐标
 * param out next: 下一步的坐标即F值最小的一个
 */
int FindNext(Node cur, Node dst, Node & next)
{
	int startx = 0; /* 遍历的横向坐标起点 */
	int starty = 0; /* 遍历的纵向坐标起点 */
	int endx = 0;   /* 遍历的横向坐标终点 */
	int endy = 0;   /* 遍历的纵向坐标终点 */

	InsertCloseList(cur);

	/* 计算坐标 */
	CalcBound(cur, startx, starty, endx, endy);

	/* 遍历找到F值最小的坐标 */
	int min = 0;
	int minx = 0;
	int miny = 0;

	Node * pnext = NULL;
	for (int i = startx; i <= endx; i++)
	{
		for (int j = starty; j <= endy; j++)
		{
			if (IsInCloseMap(i, j))
			{/* 已存在于关闭列表 */
				continue;
			}

			if (-1 == short_map[i][j])
			{/* 不可达跳过 */
				continue;
			}

			/* 找到一个相邻结点,判断是否在open_list中 a*/
			Node * node = IsInOpenMap(i, j);
			if (NULL == node)
			{
				node = new Node();
				node->x = i;
				node->y = j;
				node->px = cur.x;
				node->py = cur.y;
				node->g = CalcG(cur, i, j);
				node->h = CalcH(dst, i, j);
				node->f = node->g + node->h;

				InsertOpenList(*node);
			}
			else
			{/* 在open_list中 */
				int g = CalcG(cur, i, j);
				if ((g + cur.g) < node->g)
				{
					node->px = cur.x;
					node->py = cur.y;
					node->g = g;
					node->f = node->g + node->h;
				}
			}

			int value = node->f;
			if (0 == min || min > value)
			{
				min = value;
				pnext = node;
			}
		}
	}

	next = * pnext;

	return 0;
}

void Draw()
{
	for (int i = 0; i < ROW; i++)
	{
		for (int j =0; j < COLUMN; j++)
		{
			printf("%2d ", short_map[i][j]);
		}
		printf("\n");
	}
	printf("\n");

}

int AStar()
{
	Node Src;
	Node Dst;
	Node Cur;
	Node Next;

	/* 查找源和目的结点 */
	for (int i = 0; i < ROW; i++)
	{
		for (int j =0; j < COLUMN; j++)
		{
			if (1 == short_map[i][j])
			{
				Src.x = i; 
				Src.y = j;
				Cur.x = i;
				Cur.y = j;
			}
			
			if (2 == short_map[i][j])
			{
				Dst.x = i;
				Dst.y = j;
			}

			printf("%2d ", short_map[i][j]);
		}

		printf("\n");
	}
	printf("\n");

	/* 寻路 */
	for (int i = 0; ; i++)
	{
		FindNext(Cur, Dst, Next);

		if (Next.x == Dst.x && Next.y == Dst.y)
		{
			InsertCloseList(Next);
			break;
		}

		Cur = Next;
	}

	/* 反向绘图 */
	Node * node;
	int x = Dst.x;
	int y = Dst.y;
	
	while(1)
	{
		node = IsInCloseMap(x, y);
		
		if (NULL == node)
		{
			printf("[%d][%d]\n", x, y);
			break;
		}

		if (node->x == Src.x && node->y == Src.y)
		{
			break;
		}
	
		short_map[node->px][node->py] = 1;
		Draw();
		x = node->px;
		y = node->py;
	}
}

int main(int argc, char ** argv)
{
	AStar();
	return 0;
}


 

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值