java ARA*算法 请写注释 并实现
时间: 2024-05-08 07:21:15 浏览: 122
注释见代码:
```java
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Set;
public class AStar {
private static class Node {
int x; // 当前节点的x坐标
int y; // 当前节点的y坐标
int g; // 当前节点到起点的距离g
int f; // 当前节点到终点的预估距离f
Node parent; // 当前节点的父节点,用于回溯路径
Node(int x, int y, int g, int f, Node parent) {
this.x = x;
this.y = y;
this.g = g;
this.f = f;
this.parent = parent;
}
}
private static final int[][] DIRS = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 上下左右四个方向
/**
* A*算法,寻找起点到终点的最短路径
* @param start 起点坐标
* @param end 终点坐标
* @param obstacles 障碍物坐标集合
* @return 起点到终点的最短路径,如果不存在则返回null
*/
public static List<int[]> aStar(int[] start, int[] end, Set<int[]> obstacles) {
// 初始化起点和终点的节点
Node startNode = new Node(start[0], start[1], 0, 0, null);
Node endNode = new Node(end[0], end[1], 0, 0, null);
// 初始化open列表和closed列表
PriorityQueue<Node> open = new PriorityQueue<>(Comparator.comparingInt(node -> node.f)); // 按f值从小到大排序
Set<Node> closed = new HashSet<>();
// 将起点加入open列表
open.offer(startNode);
// 初始化节点到起点的距离g和节点到终点的预估距离f
Map<Node, Integer> gMap = new HashMap<>();
Map<Node, Integer> fMap = new HashMap<>();
gMap.put(startNode, 0);
fMap.put(startNode, getDistance(startNode, endNode));
// A*算法主循环
while (!open.isEmpty()) {
// 取出open列表中f值最小的节点
Node curr = open.poll();
// 如果当前节点是终点,则返回路径
if (curr.x == endNode.x && curr.y == endNode.y) {
return getPath(curr);
}
// 把当前节点加入closed列表
closed.add(curr);
// 遍历当前节点的四个邻居
for (int[] dir : DIRS) {
int nextX = curr.x + dir[0];
int nextY = curr.y + dir[1];
// 如果邻居节点不在地图内或是障碍物,则跳过
if (nextX < 0 || nextX >= 10 || nextY < 0 || nextY >= 10 || obstacles.contains(new int[]{nextX, nextY})) {
continue;
}
// 计算邻居节点到起点的距离g
int nextG = gMap.get(curr) + 1;
// 如果邻居节点已在closed列表中并且到起点的距离g更小,则跳过
Node next = new Node(nextX, nextY, nextG, 0, curr);
if (closed.contains(next) && nextG >= gMap.get(next)) {
continue;
}
// 否则更新邻居节点的g值和f值,加入open列表
gMap.put(next, nextG);
fMap.put(next, nextG + getDistance(next, endNode));
next.f = fMap.get(next);
open.offer(next);
}
}
// open列表为空,表示无法到达终点,返回null
return null;
}
/**
* 计算两个节点之间的曼哈顿距离
* @param a 节点a
* @param b 节点b
* @return 节点a和节点b之间的曼哈顿距离
*/
private static int getDistance(Node a, Node b) {
return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
}
/**
* 回溯路径,返回从起点到当前节点的路径
* @param node 当前节点
* @return 起点到当前节点的路径
*/
private static List<int[]> getPath(Node node) {
List<int[]> path = new ArrayList<>();
while (node != null) {
path.add(new int[]{node.x, node.y});
node = node.parent;
}
Collections.reverse(path);
return path;
}
public static void main(String[] args) {
int[] start = {0, 0};
int[] end = {9, 9};
Set<int[]> obstacles = new HashSet<>();
obstacles.add(new int[]{1, 0});
obstacles.add(new int[]{1, 1});
obstacles.add(new int[]{2, 1});
obstacles.add(new int[]{3, 1});
obstacles.add(new int[]{3, 2});
obstacles.add(new int[]{3, 3});
obstacles.add(new int[]{2, 3});
obstacles.add(new int[]{1, 3});
obstacles.add(new int[]{1, 4});
obstacles.add(new int[]{1, 5});
obstacles.add(new int[]{2, 5});
obstacles.add(new int[]{3, 5});
obstacles.add(new int[]{4, 5});
obstacles.add(new int[]{4, 4});
obstacles.add(new int[]{4, 3});
obstacles.add(new int[]{5, 3});
obstacles.add(new int[]{6, 3});
obstacles.add(new int[]{7, 3});
obstacles.add(new int[]{7, 4});
obstacles.add(new int[]{7, 5});
obstacles.add(new int[]{7, 6});
obstacles.add(new int[]{6, 6});
obstacles.add(new int[]{5, 6});
obstacles.add(new int[]{4, 6});
obstacles.add(new int[]{3, 6});
List<int[]> path = aStar(start, end, obstacles);
System.out.println(path);
}
}
```
代码的主要思路:
1. 定义节点类`Node`,存储节点的坐标、到起点的距离`g`、到终点的预估距离`f`和父节点指针`parent`。
2. 定义`aStar`方法,传入起点、终点和障碍物,返回起点到终点的最短路径。
3. 初始化起点和终点节点,以及open列表和closed列表。
4. 将起点加入open列表,初始化节点到起点的距离g和节点到终点的预估距离f。
5. 重复以下步骤,直到open列表为空:
a. 取出open列表中f值最小的节点。
b. 如果当前节点是终点,则返回路径。
c. 把当前节点加入closed列表。
d. 遍历当前节点的四个邻居,如果邻居节点不在地图内或是障碍物,则跳过。
e. 计算邻居节点到起点的距离g。
f. 如果邻居节点已在closed列表中并且到起点的距离g更小,则跳过。
g. 否则更新邻居节点的g值和f值,加入open列表。
6. open列表为空,表示无法到达终点,返回null。
7. 定义`getDistance`方法,计算两个节点之间的曼哈顿距离。
8. 定义`getPath`方法,回溯路径,返回从起点到当前节点的路径。
9. 在`main`方法中测试算法,传入起点、终点和障碍物,输出从起点到终点的最短路径。
注:本代码使用的是曼哈顿距离,也可以使用欧几里得距离或切比雪夫距离等其他距离。
阅读全文