A*(A-Star)算法是一种静态路网中求解最短路最有效的方法。估价值与实际值越接近,估价函数取得就越好,就算法本身的描述不再赘述,本例中估价值采用曼哈顿取值法,只是为了验证使用,在实际使用中建议采用其他取值法实现。
Map类和MapPoint类用于保存地图和每个地图坐标的信息:
import java.util.Vector;
/**
*
* @author xreztento@vip.sina.com
*/
public class Map {
private int width = 0;
private int length = 0;
private Vector<MapPoint> mapPoints = null;
public int getLength() {
return length;
}
public Vector<MapPoint> getMapPoints() {
return mapPoints;
}
public MapPoint getMapPoint(int x,int y)
{
int id = y * getWidth() + x;
return mapPoints.get(id);
}
public int getWidth() {
return width;
}
public void setLength(int length) {
this.length = length;
}
public void setWidth(int width) {
this.width = width;
}
public void setMapPoints(Vector<MapPoint> mapPoints) {
this.mapPoints = mapPoints;
}
}
/**
*
* @author xreztento@vip.sina.com
*/
public class MapPoint {
private int x = 0;
private int y = 0;
private int id = 0;
private float g_value = 0f;
private float h_value = 0f;
private float f_value = 0f;
private boolean isPass = true;
private boolean isRoad = false;
private MapPoint rootPoint = null;
public float getG_value() {
return g_value;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public boolean isIsPass() {
return isPass;
}
public void setG_value(float g_value) {
this.g_value = g_value;
}
public void setIsPass(boolean isPass) {
this.isPass = isPass;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public float getF_value() {
return f_value;
}
public float getH_value() {
return h_value;
}
public void setF_value(float f_value) {
this.f_value = f_value;
}
public void setH_value(float h_value) {
this.h_value = h_value;
}
public void setIsRoad(boolean isRoad) {
this.isRoad = isRoad;
}
public boolean isIsRoad() {
return isRoad;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public MapPoint getRootPoint() {
return rootPoint;
}
public void setRootPoint(MapPoint rootPoint) {
this.rootPoint = rootPoint;
}
}
AStarMethod类用于实现算法:
import java.util.Vector;
/**
*
* @author xreztento@vip.sina.com
*/
public class AStarMethod {
Vector<Integer> openList = new Vector<Integer>();
Vector<Integer> closeList = new Vector<Integer>();
private MapPoint sPoint = null;
private MapPoint dPoint = null;
private Map map = null;
public AStarMethod(MapPoint sPoint,MapPoint dPoint,Map map)
{
this.sPoint = sPoint;
this.dPoint = dPoint;
this.map = map;
}
public Vector<Integer> getRoadPoints()
{
closeList.add(sPoint.getId());
while(!closeList.contains(dPoint.getId()))
{
searchNewRootPoint(map.getMapPoints().get(closeList.get(closeList.size() - 1)));
}
return closeList;
}
public void searchNewRootPoint(MapPoint rPoint)
{
int r_x = rPoint.getX();
int r_y = rPoint.getY();
//遍历周边节点,计算f_value
for(int i = -1;i < 2;i++)
{
if(r_x + i < 0 || r_x + i >= map.getLength())//判断是否超出X轴边界
{
continue;
}
for(int j = -1;j < 2;j++)
{
if( r_y + j < 0 || r_y + j >= map.getWidth())//判断是否超出Y轴边界
{
continue;
}
float f_value = 0f;
float g_value = 0f;
float h_value = 0f;
int id = map.getMapPoint(r_x + i, r_y + j).getId();//周边节点ID
if(map.getMapPoints().get(id).isIsPass() && !closeList.contains(id) && !openList.contains(id))//节点可通过、不在open和close列表
{
map.getMapPoints().get(id).setRootPoint(rPoint);//
h_value = getHvalue(map.getMapPoints().get(id));
if(h_value == 0)//如果h_value等于0,目前节点已经找到
{
dPoint.setRootPoint(rPoint);
closeList.add(dPoint.getId());//将节点加入close列表
return;
}
if(map.getMapPoints().get(id).getX() != r_x && map.getMapPoints().get(id).getY() != r_y)//判断节点为斜侧方向节点
{
g_value = rPoint.getG_value() + 14f;
}
else
{
g_value = rPoint.getG_value() + 10f;
}
f_value = g_value + h_value;
map.getMapPoints().get(id).setF_value(f_value);
map.getMapPoints().get(id).setG_value(g_value);
map.getMapPoints().get(id).setH_value(h_value);
openList.add(id);//计算f_value值后,将节点加入open列表
}
}
}
for(int k = 0;k < openList.size() - 1;k++)//将open列表中具有最小f_value值的节点冒泡到列表最底部
{
float f_value_1 = map.getMapPoints().get(openList.get(k)).getF_value();
float f_value_2 = map.getMapPoints().get(openList.get(k + 1)).getF_value();
if(f_value_1 < f_value_2)
{
int tmp = openList.get(k);
openList.set(k,openList.get(k + 1));
openList.set(k + 1,tmp);
}
}
if(openList.size() > 0)//如果open列表不为空
{
int id = openList.get(openList.size() - 1);
openList.remove(openList.size() - 1);
closeList.add(id);//将具有最小f_value值得节点加入close列表
}
else//如果open列表为空,未找到路径
{
closeList.add(dPoint.getId());
return;
}
}
public float getHvalue(MapPoint point)
{
//曼哈顿取值法
return (Math.abs(point.getX() - dPoint.getX()) + Math.abs(point.getY() - dPoint.getY()))*10;
//实际应用时使用其他取值法
}
}
MakeMap类用于初始化一张图:
import java.util.Vector;
/**
*制造一张图
* @author xreztento@vip.sina.com
*/
public class MakeMap {
public void initialMap(Map map,int mapWidth,int mapLength)
{
map.setWidth(mapWidth);
map.setLength(mapLength);
java.util.Vector<MapPoint> mapPoints = new Vector<MapPoint>(mapWidth * mapLength);
for(int i = 0;i < mapWidth;i++)
{
for(int j = 0;j < mapLength;j++)
{
MapPoint mp = new MapPoint();
mp.setX(j);
mp.setY(i);
mp.setId(i * mapWidth + j);
mapPoints.add(mp);
}
}
map.setMapPoints(mapPoints);
}
}
AStar类用于使用算法和测试:
/**
*
* @author xreztento@vip.sina.com
*/
public class AStar {
public static void main(String[] args) {
MakeMap mm = new MakeMap();
Map map = new Map();
//Map map,int mapWidth,int mapLength
mm.initialMap(map, 20,20);
map.getMapPoint(3, 1).setIsPass(false);
map.getMapPoint(3, 2).setIsPass(false);
map.getMapPoint(3, 3).setIsPass(false);
map.getMapPoint(3, 4).setIsPass(false);
map.getMapPoint(0, 6).setIsPass(false);
map.getMapPoint(1, 6).setIsPass(false);
map.getMapPoint(2, 6).setIsPass(false);
map.getMapPoint(3, 6).setIsPass(false);
map.getMapPoint(4, 6).setIsPass(false);
map.getMapPoint(5, 6).setIsPass(false);
map.getMapPoint(6, 6).setIsPass(false);
map.getMapPoint(3, 7).setIsPass(false);
map.getMapPoint(4, 7).setIsPass(false);
map.getMapPoint(5, 7).setIsPass(false);
map.getMapPoint(6, 7).setIsPass(false);
map.getMapPoint(7, 7).setIsPass(false);
map.getMapPoint(8, 7).setIsPass(false);
map.getMapPoint(9, 7).setIsPass(false);
map.getMapPoint(10, 7).setIsPass(false);
map.getMapPoint(11, 7).setIsPass(false);
map.getMapPoint(12, 7).setIsPass(false);
map.getMapPoint(9, 8).setIsPass(false);
map.getMapPoint(9, 9).setIsPass(false);
map.getMapPoint(9, 10).setIsPass(false);
map.getMapPoint(9, 11).setIsPass(false);
long beginTime = System.currentTimeMillis();
AStarMethod asm = new AStarMethod(map.getMapPoint(0, 1),map.getMapPoint(8, 9),map);
asm.getRoadPoints();
searchRoad(map.getMapPoint(0, 1),map.getMapPoint(8, 9));
long endTime = System.currentTimeMillis();
System.out.println("A-star compute time is " + (endTime - beginTime) + "ms");
for(int i = 0;i < map.getLength() * map.getWidth();i++)
{
MapPoint mp = map.getMapPoints().get(i);
if((mp.getX() + 1) % (map.getLength()) == 0)
{
if(mp.isIsPass())
{
if(mp.isIsRoad())
{
System.out.print("#\n");
}
else
{
System.out.print("*\n");
}
}
else
{
System.out.print("+\n");
}
}
else
{
if(mp.isIsPass())
{
if(mp.isIsRoad())
{
System.out.print("#");
}
else
{
System.out.print("*");
}
}
else
{
System.out.print("+");
}
}
}
}
public static void searchRoad(MapPoint s,MapPoint e)//从终点迭代每个节点所指向的父节点,直到起点
{
if(e.getRootPoint() == s)//如果到达起点,终止迭代
{
e.setIsRoad(true);
return;
}
else
{
e.setIsRoad(true);
searchRoad(s,e.getRootPoint());//迭代
}
}
}
测试结果如下图所示: