A算法是一种常用且高效的启发式搜索算法。
1. 背景
- A*算法是一种基于启发式搜索的路径规划算法,结合了Dijkstra算法的广度优先搜索和贪婪最佳优先搜索的优点。
2. 基本原理
- 广度优先搜索很傻,各个点邻点都要依次探索,于是改善,选择当前代价最低的点去探索,为A*算法。
- A*算法使用两个关键函数(代价)来决定搜索路径,其中:
- f(n) 存储总代价。
- g(n) 是当前代价,比如你从起点走到位置A会花多少代价(格子数,时间...)。
- h(n)是预估代价,表示从位置A走到终点大概走多少步,非精确数值。常用的预估代价方式有欧拉距离(当前位置和终点的直线距离大小),或曼哈顿距离(把当前位置和终点当成矩形的对角两点,曼哈顿距离就是长+宽)
- 则点的总代价为f(n)=g(n)+h(n),每次都选择代价最小的点进行探索(出队列)到达即结束,此时队列大概率不为空。而不是像一般的BFS把所有节点都入队列出队列清空才结束。
3. 伪代码
函数 AStar(地图, 起点, 终点):
初始化优先队列 openList
将起点加入 openList
初始化 visited 数组,标记所有节点为未访问
while openList 非空:
当前节点 = openList 中代价最小的节点
从 openList 中移除当前节点
如果当前节点是终点:
输出找到路径
返回
将当前节点标记为已访问
对当前节点的所有邻居节点:
计算邻居节点的代价 g
计算邻居节点的总代价 f = g + 曼哈顿距离(邻居节点, 终点)
如果邻居节点未访问过:
将邻居节点加入 openList
标记邻居节点为已访问
输出未找到路径
4. 优点与局限
- 优点:
- 可以找到最优解(如果启发式函数满足一定条件)。
- 在启发式函数良好选择时,速度较快。
- 局限:
- 启发式函数的选择会影响搜索效率。
- 可能会受到地图网格分辨率等因素的影响。
C++代码实现(广泛的邻接表)示例:
#include <iostream>
#include <vector>
#include <queue>
#include <cmath>
#include <algorithm>
using namespace std;
// 定义地图节点结构
struct Node {
int x, y; // 节点坐标
int f, g; // 总代价 f 和起点到该节点的代价 g
};
// 自定义比较函数,用于优先队列的排序
struct CompareNode {
bool operator()(const Node &a, const Node &b) {
return a.f > b.f;
}
};
// 计算曼哈顿距离
int calculateManhattanDistance(Node a, Node b) {
return abs(a.x - b.x) + abs(a.y - b.y);
}
// A*算法实现
void AStar(vector<vector<int>>