a*算法是搜索最短路径的算法(曼哈顿距离)。
你要记住一个公式 F=G(从起点到该放个的当前最小消耗)+H(预估到终点距离)
整个搜索过程中有:
graph[][]搜索地图, used搜索过的节点集合,waiting 等待搜索的节点集合。
起始点 start,终点 end
1:将 start 放入 waiting
2:从 waiting 中取出 F 最小并且不在 used 中的节点为当前节点 now,将 now 放入 used。
3:遍历 now 周边联通、不再 used 中的节点 around。
如果没在 waiting 中:将 around 的父节点设置为 now,然后将 around 加入 waiting 中。
如果存在 waiting 中:如果 around 的 G 值更高:什么都不作,如果 around.G 低将 waiting[around].G = around.G 并重新计算 F waiting[around].parrent = around。
4:循环 2,3 直到 end 添加到 used 中。
5:路径即 end.parent 这条链路。
public static int MAX_X = 10;
public static int MAX_Y = 10;
static class Node{
int x;// 点的位置X
int y;// 点的位置Y
int F;// F = G + H
int G;// 从起点到该点的最小消耗
int H;// 预估到终点的距离
Node parent;
public void countH(Node to){
int disX = to.x - this.x;
int disY = to.y - this.y;
this.H = Math.abs(disX) + Math.abs(disY);
}
public void countF(){
this.F = this.G + this.H;
}
public Node up(Node to){
return nextNode(0, -1, to);
}
public Node down(Node to){
return nextNode(0, 1, to);
}
public Node left(Node to){
return nextNode(-1, 0, to);
}
public Node right(Node to){
return nextNode(1, 0, to);
}
public Node nextNode(int incrementX, int incrementY, Node to){
Node node = new Node();
node.x = this.x + incrementX;
node.y = this.y + incrementY;
node.G = this.G + 1;
node.countH(to);
node.countF();
node.parent = this;
return node;
}
}
/**
* node是否在图内
* @param node
* @param maxX
* @param maxY
* @return
*/
private static boolean inRange(Node node, int maxX, int maxY){
return node.x >= 0 && node.x <= maxX && node.y >= 0 && node.y <= maxY;
}
/**
* 是否x,y坐标相等
* @param node
* @param node2
* @return
*/
private static boolean equals(Node node, Node node2){
return node != null && node2 != null && node.x == node2.x && node.y == node2.y;
}
public static void main(String[] args) {
@SuppressWarnings("resource")
Scanner scan = new Scanner(System.in);
int[][] graph = InputUtils.getGraph();
MAX_X = MAX_Y = graph.length - 1;
LOG.d("to index:x y");
Node to = new Node();
to.x = scan.nextInt();
to.y = scan.nextInt();
LOG.d("from index:x y");
Node from = new Node();
from.x = scan.nextInt();
from.y = scan.nextInt();
from.countH(to);
axing(graph, from, to);
}
public static void axing(int[][] graph, Node from, Node to){
List<Node> waiting = new ArrayList<>();
List<Node> used = new ArrayList<>();
waiting.add(from);
while (waiting.size() > 0){
Node min = findMinWithF(waiting, used);
used.add(min);
if (equals(min, to)){
printLine(min);
printLineGraph(graph, min);
break;
}
addAroundToWaiting(graph, waiting, used, min, to);
}
}
private static void printLineGraph(int[][] graph, Node end){
while (end != null){
graph[end.y][end.x] = 3;
end = end.parent;
}
printGraph(graph);
}
private static void printGraph(int[][] graph){
for (int i = 0; i < graph.length; i++){
for (int j = 0; j < graph[i].length; j++){
if (graph[i][j] == 1){
System.out.print("_ ");
} else if (graph[i][j] == 3){
System.out.print("* ");
} else {
System.out.print("X ");
}
}
System.out.println();
}
}
private static void printLine(Node end){
while (end != null){
LOG.d("short line:(", end.x, ",", end.y, ")");
end = end.parent;
}
}
/**
* 添加到等待开启列表
* @param waiting
* @param used
* @param node
*/
private static void addToWaiting(int[][] graph, List<Node> waiting, List<Node> used, Node node){
if (!inRange(node, MAX_X, MAX_Y)){
return;
}
if (graph[node.y][node.x] == 0){
return;
}
if (inUsed(used, node)){
return;
}
if (!changeInWaiting(waiting, node)){
waiting.add(node);
}
}
/**
* 是否在关闭列表中
* @param used
* @param node
* @return
*/
private static boolean inUsed(List<Node> used, Node node){
return findInList(used, node) != null;
}
/**
* 是否在列表中存在
* @param list
* @param node
* @return
*/
private static Node findInList(List<Node> list, Node node){
for (Node n : list){
if (equals(n, node)){
return n;
}
}
return null;
}
/**
* 在开启列表中修改G值
* @param waiting
* @param node
* @return 修改成功返回 true 失败返回 false
*/
private static boolean changeInWaiting(List<Node> waiting, Node node){
for (Node n : waiting){
if (equals(n, node)){
if (n.G > node.G){
n.parent = node.parent;
return true;
}
}
}
return false;
}
/**
* 获取列表中F最小的点
* @param waiting
* @return
*/
private static Node findMinWithF(List<Node> waiting, List<Node> used){
Node min = null;
int minIndex = -1;
for (int i = 0; i < waiting.size(); i++){
if (!inUsed(used, waiting.get(i))){
if (min == null || min.F > waiting.get(i).F){
minIndex = i;
min = waiting.get(i);
}
}
}
if (minIndex != -1)
waiting.remove(minIndex);
return min;
}
/**
* 添加周边点进入等待开启列表
* @param waiting
* @param used
* @param node
* @param to
*/
private static void addAroundToWaiting(int[][] graph, List<Node> waiting, List<Node> used, Node node, Node to){
Node up = node.up(to);
addToWaiting(graph, waiting, used, up);
Node down = node.down(to);
addToWaiting(graph, waiting, used, down);
Node left = node.left(to);
addToWaiting(graph, waiting, used, left);
Node right = node.right(to);
addToWaiting(graph, waiting, used, right);
}