A*算法是一种启发式搜索算法,结合了Dijkstra的最短路径保证和贪心搜索的效率。它使用估价函数 f(n) = g(n) + h(n) 来指导搜索方向。

起点 终点 障碍物 待探索 已探索 最短路径
点击网格绘制/清除障碍物
点击"开始"查看动画

核心概念

  • g(n):从起点到节点n的实际代价
  • h(n):从节点n到终点的启发式估计(如曼哈顿距离)
  • f(n) = g(n) + h(n):节点n的总估价
  • 每次从Open列表中选择f值最小的节点扩展
  • 当选中的节点是终点时,搜索结束

启发函数h(n)必须是"可采纳的"(不高估实际代价),才能保证找到最短路径。

时间与空间复杂度

指标 复杂度 说明
时间复杂度 O(E) 最坏情况,取决于启发函数质量
实际性能 远优于Dijkstra 启发式引导减少探索节点
空间复杂度 O(V) 存储Open和Closed列表

A* vs Dijkstra:Dijkstra向所有方向均匀扩展,而A*优先向目标方向探索。

应用场景

  • 游戏中的NPC寻路和单位移动
  • 机器人路径规划
  • GPS导航系统
  • 自动驾驶路径决策
  • 物流配送路线优化
游戏开发 机器人导航 自动驾驶 物流优化

代码实现

import heapq

def heuristic(a, b):
    """曼哈顿距离"""
    return abs(a[0] - b[0]) + abs(a[1] - b[1])


def astar(grid, start, goal):
    """A*寻路算法
    grid: 2D网格, 0=可通行, 1=障碍
    """
    rows, cols = len(grid), len(grid[0])
    
    # 四方向移动
    directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
    
    open_set = []
    heapq.heappush(open_set, (0, start))
    
    came_from = {}
    g_score = {start: 0}
    f_score = {start: heuristic(start, goal)}
    
    while open_set:
        _, current = heapq.heappop(open_set)
        
        if current == goal:
            # 重建路径
            path = []
            while current in came_from:
                path.append(current)
                current = came_from[current]
            path.append(start)
            return path[::-1]
        
        for dx, dy in directions:
            neighbor = (current[0] + dx, current[1] + dy)
            
            # 边界和障碍检查
            if (0 <= neighbor[0] < rows and
                0 <= neighbor[1] < cols and
                grid[neighbor[0]][neighbor[1]] == 0):
                
                tentative_g = g_score[current] + 1
                
                if tentative_g < g_score.get(neighbor, float('inf')):
                    came_from[neighbor] = current
                    g_score[neighbor] = tentative_g
                    f = tentative_g + heuristic(neighbor, goal)
                    heapq.heappush(open_set, (f, neighbor))
    
    return None  # 无路径
import java.util.*;

public class AStar {
    
    static int heuristic(int[] a, int[] b) {
        return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]);
    }
    
    public static List<int[]> astar(
            int[][] grid, int[] start, int[] goal) {
        
        int rows = grid.length, cols = grid[0].length;
        int[][] dirs = {{0,1}, {1,0}, {0,-1}, {-1,0}};
        
        // 优先队列: [f值, x, y]
        PriorityQueue<int[]> openSet = new PriorityQueue<>(
            (a, b) -> a[0] - b[0]
        );
        
        Map<String, int[]> cameFrom = new HashMap<>();
        Map<String, Integer> gScore = new HashMap<>();
        
        String startKey = start[0] + "," + start[1];
        gScore.put(startKey, 0);
        openSet.offer(new int[]{
            heuristic(start, goal), start[0], start[1]
        });
        
        while (!openSet.isEmpty()) {
            int[] curr = openSet.poll();
            int x = curr[1], y = curr[2];
            
            if (x == goal[0] && y == goal[1]) {
                // 重建路径
                return reconstructPath(cameFrom, goal);
            }
            
            for (int[] d : dirs) {
                int nx = x + d[0], ny = y + d[1];
                if (nx >= 0 && nx < rows && ny >= 0 && ny < cols
                    && grid[nx][ny] == 0) {
                    // 更新邻居...
                }
            }
        }
        return null;
    }
}