赞
踩
A*算法(A-star algorithm)是一种常用的启发式搜索算法,用于求解图中两个节点之间的最短路径。A算法综合了Dijkstra算法的广度优先搜索和贪婪最优搜索策略,通过使用估计函数(heuristic function)来指导搜索方向,从而提高搜索效率。
以下是A*算法的详细步骤:
A*算法使用了一个估计函数来指导搜索,在每次选择下一个节点时,它考虑了两个值:g值和h值。
A*算法的估计函数f值定义为:f(n) = g(n) + h(n),其中n是当前节点。f值越小,越有可能是优先考虑的节点。
A*算法的性能和效果取决于所选择的估计函数。一个好的估计函数应该能够提供较为准确的估计值,以便更好地引导搜索,但也需要具备一定的效率,以免过多地增加计算复杂度。
A算法的优点是在适当的估计函数下,能够找到最短路径,并且相对于其他完全搜索算法,它的搜索效率更高。然而,A算法并不能保证一定找到最短路径,且在某些情况下可能会陷入局部最优解。
- class Node {
- int x; // 节点的x坐标
- int y; // 节点的y坐标
- int g; // 从起始节点到当前节点的实际代价
- int h; // 从当前节点到目标节点的估计代价
- int f; // 估计函数值
- Node parent; // 父节点
-
- public Node(int x, int y) {
- this.x = x;
- this.y = y;
- }
- // 必须重写equals方法
- @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);
- }
- }
- public class AStar {
- public static void main(String[] args) {
- int[][] grid = {
- {0, 0, 0, 0, 0},
- {1, 1, 0, 1, 0},
- {0, 0, 0, 0, 0},
- {0, 1, 1, 1, 1},
- {0, 0, 0, 0, 0}
- };
-
- Node start = new Node(0, 0);
- Node end = new Node(4, 4);
-
- List<Node> path = findShortestPath(grid, start, end);
-
- if (path != null) {
- for (Node node : path) {
- System.out.print("(" + node.x + ", " + node.y + ")");
- System.out.print("-> ");
- }
- System.out.print("end");
- } else {
- System.out.println("No path found");
- }
- }
- public static List<Node> findShortestPath(int[][] grid, Node start, Node end) {
- int rows = grid.length;
- int cols = grid[0].length;
- //创建开放 关闭列表
- List<Node> openList = new ArrayList<>();
- List<Node> closeList = new ArrayList<>();
- //初始化开始节点
- start.g = 0;// 从起始节点到当前节点的实际代价
- start.h = calculateHeuristic(start, end);// 从当前节点到目标节点的估计代价
- start.f = start.g + start.h;
- //添加进开放列表
- openList.add(start);
- //开放列表不为null就一直循环
- while (!openList.isEmpty()) {
- //从开放列表中选f最小的节点
- Node current = getMinimumFValueNode(openList);
- //将当前节点从开放列表中删除
- openList.remove(current);
- //加入关闭列表
- closeList.add(current);
- if (current.equals(end)) {
- //找到最短路径,回溯到起始节点
- return buildPath(current);
- }
- //当前节点的邻居节点
- List<Node> neighbors = getNeighbors(current, grid, rows, cols);
- for (Node neighbor : neighbors) {
- if(closeList.contains(neighbor)){
- //已访问
- continue;
- }
- //当前节点移动到邻居节点 实际代价为1
- int tentativeG = current.g+1;
- // 如果开放列表中没有该几点,或者 存在该几点但是之走前路径的代价较大
- if(!openList.contains(neighbor)||tentativeG<neighbor.g){
- neighbor.parent = current;
- neighbor.g = tentativeG;
- neighbor.h = calculateHeuristic(neighbor,end);
- neighbor.f=neighbor.g+neighbor.h;
- //已经在里面 就不要添加了
- if(!openList.contains(neighbor)){
- openList.add(neighbor);
- }
- }
- }
-
- }
- return null; //无法找到最短路径
- }
- // 计算预估代价
- private static int calculateHeuristic(Node current, Node end) {
- // 使用曼哈顿距离作为估计函数
- return Math.abs(current.x - end.x) + Math.abs(current.y - end.y);
- }
- // 得到列表中 f 最小的节点
- private static Node getMinimumFValueNode(List<Node> nodes) {
- int minF = Integer.MAX_VALUE;
- Node minNode = null;
- for (Node node : nodes) {
- if (node.f < minF) {
- minF = node.f;
- minNode = node;
- }
- }
- return minNode;
- }
- // 通过节点的parent 构建出路径
- private static List<Node> buildPath(Node node) {
- List<Node> path = new ArrayList<>();
- while (node != null) {
- path.add(0, node);
- node = node.parent;
- }
- return path;
- }
- // 得到邻居节点列表
- private static List<Node> getNeighbors(Node node, int[][] grid, int rows, int cols) {
- List<Node> neighbors = new ArrayList<>();
- int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 上下左右四个方向
- for (int[] direction : directions) {
- int newX = node.x + direction[0];
- int newY = node.y + direction[1];
- if (newX >= 0 && newX < rows && newY >= 0 && newY < cols && grid[newX][newY] == 0) {
- // 邻居节点在有效范围内且不是障碍物
- Node neighbor = new Node(newX, newY);
- neighbors.add(neighbor);
- }
- }
- return neighbors;
- }
- }
- public class AStarPriority {
-
- public static void main(String[] args) {
- int[][] grid = {
- {0, 0, 0, 0, 0},
- {1, 1, 0, 1, 0},
- {0, 0, 0, 0, 0},
- {0, 1, 1, 1, 1},
- {0, 0, 0, 0, 0}
- };
-
- Node start = new Node(0, 0);
- Node end = new Node(4, 4);
-
- List<Node> path = findShortestPath(grid, start, end);
-
- if (path != null) {
- for (Node node : path) {
- System.out.print("(" + node.x + ", " + node.y + ")");
- System.out.print("-> ");
- }
- System.out.print("end");
- } else {
- System.out.println("No path found");
- }
- }
-
-
- public static List<Node> findShortestPath(int[][] grid, Node start, Node end) {
- int rows = grid.length;
- int cols = grid[0].length;
- //优先队列
- PriorityQueue<Node> queue = new PriorityQueue<>(rows + cols, Comparator.comparingInt(o -> o.f));
- //已访问的节点
- Set<Node> visited = new HashSet<>(rows + cols);
- //处理开始节点
- start.g = 0; //开始几点到当前节点的代价
- start.h = guess(start, end); //猜测当前节点到终点的代价
- //计算的代价
- start.f = start.g + start.h;
- //将当前节点添加到优先队列中
- queue.offer(start);
- while (!queue.isEmpty()) {
- //代价最小(f最小)的节点出队列
- Node current = queue.poll();
- //将当前节点加入 已访问
- visited.add(current);
- //如果当前节点等于end
- if (current.equals(end)) {
- //找到了
- return buildPath(current);
- }
- //当前节点的邻居
- List<Node> neighbors = currentNeighbors(current, grid, rows, cols);
- //遍历邻居
- for (Node neighbor : neighbors) {
- //访问过 就跳过
- if (visited.contains(neighbor))
- continue;
- //从当前节点到邻居 花费代价1
- int tentativeG = current.g + 1;
- //如果当前节点没有在队列中 或者 当前路径代价更小
- if (!queue.contains(neighbor) || tentativeG < neighbor.g) {
- //更新邻居节点
- neighbor.parent = current;
- neighbor.g = tentativeG;
- neighbor.h = guess(neighbor, end);
- neighbor.f = neighbor.g + neighbor.h;
- if(!queue.contains(neighbor)){
- queue.offer(neighbor);
- }
- }
- }
- }
- return null;
- }
-
- private static List<Node> currentNeighbors(Node current, int[][] grid, int rows, int cols) {
- //上下左右4个方向
- int[][] dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
- List<Node> neighbors = new ArrayList<>();
- for (int[] d : dir) {
- int nx = current.x + d[0];//下一个几点的x
- int ny = current.y + d[1];//下一个几点的y
- //是否合法
- if (nx < 0 || nx >= rows || ny < 0 || ny >= cols || grid[nx][ny] == 1)
- continue;
- neighbors.add(new Node(nx, ny));
- }
- return neighbors;
- }
-
- private static List<Node> buildPath(Node current) {
- List<Node> path = new ArrayList<>();
- Node temp = current;
- while (temp != null) {
- path.add(0,temp);
- temp = temp.parent;
- }
- return path;
- }
-
- private static int guess(Node current, Node end) {
- //当前节点到终点的曼哈顿距离: 曼哈顿距离比直线距离好算,不用开方
- return Math.abs(current.x - end.x) + Math.abs(current.y - end.y);
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。