用了一天来学习这个算法,好歹是写出程序来了。
我是从某个前辈的博客学习的A*算法,想看原文可以点击这里。不过这篇译文有些问题,比如一些数字没有显示出来,这算比较次要的,主要的是后面循环寻路说的有些模糊,我和舍友推了一下午,后来才算明白过来。
下面我来在上文基础上,简化成二维矩阵的A*寻路问题来讲一些心得体会。
首先,A*的关键寻路函数:f = g + h。g是 从起点到该节点 按照所选路径走 所需要的花费。h是该节点到终点的曼哈顿距离*常数。按我理解,这个常数是为了保持g和h在一个数量级上,以免让g或h单独做大。
另外,本文所采用代码用到了优先队列,不了解可以看这个博客——优先队列的使用
我们从开启列表中选择F值最低的节点。然后,对选中的节点做如下处理:
1.把它从开启队列删除,然后添加到关闭列表中。
//先把起始节点赋给当前节点,并放入关闭队列
current = _start;
close.push(current);
2.检查所有相邻格子。跳过那些已经在关闭列表中的或者不可通过的(有墙,水的地形,或者其他无法通过的地形),把他们添加进开启列表,如果他们还不在里面的话。 把选中的方格作为新的方格的父节点。
//开始寻路
while (true) {
int x = 0,y = 0;
for (int i = 0; i < 4; i++) {//向四个方向寻路
x = current.position.x + des[i].x;
y = current.position.y + des[i].y;
if (map[x][y]!=2&&(!findInClose(x,y))) {//判断是否是墙,或者是否存在于关闭队列
node q;
q.father = new node;
*(q.father) = current;
q.position.x = x;
q.position.y = y;
q.fx = f(q);
q.gx = g(q);
q.hx = h(q);
open.push(q);//把寻到的节点放入开启队列
}
if (map[x][y]==3) {//如果找到终点就停止
break;
}
}
current = open.top();//当前节点 等于 开启队列中的最优节点
open.pop();//从开启队列中删除放入关闭队列
close.push(current);
if (map[x][y]==3) {
break;
}
}
//寻路完毕,所有最优节点都已放入关闭队列
3.*如果某个相邻格已经在开启列表里了,检查现在的这条路径是否更好。换句话说,检查如果我们用新的路径到达它的话,G值是否会更低一些。如果不是,那就什么都不做。另一方面,如果新的G值更低,那就把相邻方格的父节点改为目前选中的方格(在上面的图表中,把箭头的方向改为指向这个方格)。最后,重新计算F和G的值。(这一段话在本文中没有用处,因为本文中节点前进只有4个方向,不存在对角线方向,也不存在G值更低的点)(此处存疑,未发现问题,也不知道对不对)。