A*算法和ARA*算法的区别
时间: 2023-11-13 10:05:26 浏览: 259
A*算法和ARA*算法都是基于启发式搜索的算法,用于解决最短路径问题。
A*算法是一种启发式搜索算法,它通过综合考虑从起点到当前节点的代价和从当前节点到终点的估价来选择下一个节点进行扩展,以此来尽可能快地找到到达终点的最短路径。A*算法在搜索空间较小的情况下,能够很快地找到最优解,但在搜索空间较大时,其搜索效率会下降。
ARA*算法是对A*算法的改进,它可以在保证最优解的情况下,减少搜索空间,提高搜索效率。ARA*算法允许在搜索过程中,逐步缩小启发函数的值,从而逐步放宽对最优解的要求。具体来说,ARA*算法在搜索过程中维护一个阈值,每次搜索时只扩展估价函数值小于该阈值的节点。如果找到了一条路径,其代价小于当前阈值,则该路径一定是最优解;否则,将阈值逐步降低,重新进行搜索,直到找到最优解为止。
因此,ARA*算法相比于A*算法,能够更加高效地搜索最短路径,但是需要在保证最优解的同时,进行一定的路径重复搜索。
相关问题
java ARA*算法 请写注释
以下是 Java 实现的 ARA* 算法,含有注释:
```java
import java.util.*;
public class ARAStar {
private static final int INFINITY = Integer.MAX_VALUE; // 定义无穷大值为整数最大值
private static final int OBSTACLE = -1; // 定义障碍物的值为 -1
private int[][] grid; // 二维网格地图
private int rows, cols; // 地图的行数和列数
private int startX, startY; // 起点的坐标
private int goalX, goalY; // 终点的坐标
private double epsilon; // 权重因子
private int[][] gValues; // g 值矩阵
private int[][] rhsValues; // rhs 值矩阵
private PriorityQueue<Node> openSet; // 优先队列存储待扩展的节点
private Map<Node, Integer> gValuesMap; // g 值的哈希表,用于快速查找节点的 g 值
private Map<Node, Integer> rhsValuesMap; // rhs 值的哈希表,用于快速查找节点的 rhs 值
// 构造函数
public ARAStar(int[][] grid, int startX, int startY, int goalX, int goalY, double epsilon) {
this.grid = grid;
this.rows = grid.length;
this.cols = grid[0].length;
this.startX = startX;
this.startY = startY;
this.goalX = goalX;
this.goalY = goalY;
this.epsilon = epsilon;
this.gValues = new int[rows][cols];
this.rhsValues = new int[rows][cols];
this.openSet = new PriorityQueue<>();
this.gValuesMap = new HashMap<>();
this.rhsValuesMap = new HashMap<>();
initialize();
}
// 初始化各个数据结构
private void initialize() {
// 将所有格子的 g 值和 rhs 值初始化为无穷大
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
gValues[i][j] = INFINITY;
rhsValues[i][j] = INFINITY;
}
}
// 将终点的 rhs 值设为 0
rhsValues[goalX][goalY] = 0;
// 将终点加入到优先队列中
openSet.offer(new Node(goalX, goalY, calculateKey(goalX, goalY)));
// 将终点的 rhs 值和优先队列中的节点的 rhs 值添加到哈希表中
rhsValuesMap.put(new Node(goalX, goalY), 0);
gValuesMap.put(new Node(goalX, goalY), INFINITY);
}
// 计算指定节点的启发式函数值
private double heuristic(int x, int y) {
return Math.sqrt(Math.pow(x - goalX, 2) + Math.pow(y - goalY, 2));
}
// 计算指定节点的 key 值
private Key calculateKey(int x, int y) {
int gValue = gValues[x][y];
int rhsValue = rhsValues[x][y];
return new Key(Math.min(gValue, rhsValue) + epsilon * heuristic(x, y), Math.min(gValue, rhsValue));
}
// 更新指定节点的 g 值
private void updateGValue(Node node) {
int x = node.x;
int y = node.y;
gValues[x][y] = INFINITY;
for (Node neighbor : getNeighbors(node)) {
int cost = getCost(node, neighbor);
if (rhsValues[neighbor.x][neighbor.y] + cost < gValues[x][y]) {
gValues[x][y] = rhsValues[neighbor.x][neighbor.y] + cost;
}
}
gValuesMap.put(node, gValues[x][y]);
}
// 更新指定节点的 rhs 值
private void updateRHSValue(Node node) {
if (!node.equals(new Node(goalX, goalY)) && !isObstacle(node.x, node.y)) {
rhsValues[node.x][node.y] = INFINITY;
for (Node neighbor : getNeighbors(node)) {
int cost = getCost(node, neighbor);
if (gValues[neighbor.x][neighbor.y] + cost < rhsValues[node.x][node.y]) {
rhsValues[node.x][node.y] = gValues[neighbor.x][neighbor.y] + cost;
}
}
}
rhsValuesMap.put(node, rhsValues[node.x][node.y]);
}
// 判断指定节点是否为障碍物
private boolean isObstacle(int x, int y) {
return grid[x][y] == OBSTACLE;
}
// 获取指定节点的邻居节点
private List<Node> getNeighbors(Node node) {
int x = node.x;
int y = node.y;
List<Node> neighbors = new ArrayList<>();
if (x > 0) neighbors.add(new Node(x - 1, y));
if (y > 0) neighbors.add(new Node(x, y - 1));
if (x < rows - 1) neighbors.add(new Node(x + 1, y));
if (y < cols - 1) neighbors.add(new Node(x, y + 1));
return neighbors;
}
// 获取指定节点到邻居节点的代价
private int getCost(Node node, Node neighbor) {
if (isObstacle(neighbor.x, neighbor.y)) {
return INFINITY;
}
return 1;
}
// 执行 ARA* 算法
public List<Node> run() {
while (true) {
if (openSet.isEmpty()) {
return null;
}
Node node = openSet.peek();
if (calculateKey(node.x, node.y).compareTo(node.key) < 0) {
openSet.poll();
node.key = calculateKey(node.x, node.y);
openSet.offer(node);
} else if (gValues[node.x][node.y] > rhsValues[node.x][node.y]) {
updateGValue(node);
for (Node neighbor : getNeighbors(node)) {
if (!neighbor.equals(new Node(startX, startY))) {
updateRHSValue(neighbor);
}
if (gValues[neighbor.x][neighbor.y] > rhsValues[neighbor.x][neighbor.y]) {
if (openSet.contains(neighbor)) {
openSet.remove(neighbor);
}
neighbor.key = calculateKey(neighbor.x, neighbor.y);
openSet.offer(neighbor);
} else if (gValues[neighbor.x][neighbor.y] < rhsValues[neighbor.x][neighbor.y] && openSet.contains(node)) {
if (openSet.contains(node)) {
openSet.remove(node);
}
node.key = calculateKey(node.x, node.y);
openSet.offer(node);
}
}
} else {
int pathLength = gValues[startX][startY];
List<Node> path = new ArrayList<>();
path.add(new Node(startX, startY));
while (!path.get(path.size() - 1).equals(new Node(goalX, goalY))) {
Node current = path.get(path.size() - 1);
List<Node> neighbors = getNeighbors(current);
Node next = null;
int minCost = INFINITY;
for (Node neighbor : neighbors) {
int cost = getCost(current, neighbor);
if (gValues[neighbor.x][neighbor.y] + cost < minCost) {
next = neighbor;
minCost = gValues[neighbor.x][neighbor.y] + cost;
}
}
path.add(next);
}
return path;
}
}
}
// 表示地图中的一个节点
private static class Node {
int x;
int y;
Key key;
public Node(int x, int y) {
this.x = x;
this.y = y;
}
public Node(int x, int y, Key key) {
this.x = x;
this.y = y;
this.key = key;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Node node = (Node) o;
return x == node.x &&
y == node.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
// 表示节点的 key 值,用于在优先队列中排序
private static class Key implements Comparable<Key> {
double first;
int second;
public Key(double first, int second) {
this.first = first;
this.second = second;
}
@Override
public int compareTo(Key other) {
if (first < other.first) {
return -1;
} else if (first > other.first) {
return 1;
} else if (second < other.second) {
return -1;
} else if (second > other.second) {
return 1;
} else {
return 0;
}
}
}
}
```
主要思路如下:
1. 初始化 ARA* 算法的各个数据结构。
2. 将终点加入到优先队列中,并将其 rhs 值设为 0。
3. 不断从优先队列中取出 key 值最小的节点进行扩展,直到找到起点或优先队列为空为止。
4. 如果当前节点的 key 值小于其存储的 key 值,则更新其 key 值并重新加入到优先队列中。
5. 否则,如果当前节点的 g 值大于其 rhs 值,则更新其 g 值,并对其所有邻居节点进行更新操作。
6. 如果某个邻居节点的 g 值小于其 rhs 值,则将其添加到优先队列中。
7. 如果某个邻居节点的 g 值大于其 rhs 值,则将当前节点添加到优先队列中。
8. 如果当前节点的 g 值等于其 rhs 值,并且其为起点,则找到了一条最短路径,返回该路径。
9. 否则,继续执行步骤 3。
注释中对各个函数的作用进行了说明,可以结合代码一起理解。
java ARA*算法 请写注释 并实现
注释见代码:
```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`方法中测试算法,传入起点、终点和障碍物,输出从起点到终点的最短路径。
注:本代码使用的是曼哈顿距离,也可以使用欧几里得距离或切比雪夫距离等其他距离。
阅读全文