A*算法(A-star algorithm)是一种广泛应用于路径规划和图搜索的启发式搜索算法。它结合了广度优先搜索的全面性和深度优先搜索的效率,通过估计当前路径代价和到达目标的预估代价,来找到从起点到目标的最短路径。A算法在游戏开发、机器人导航和人工智能等领域中非常常见,因为它可以有效地处理复杂的搜索空间并找到最优解。
在A*算法中,节点有三个重要参数:
- g值:从起点到当前节点的实际代价。
- h值:从当前节点到目标节点的预估代价,通常通过启发式函数(如曼哈顿距离或欧几里得距离)来计算。
- f值:f = g + h,用于评估当前节点的优先级,f值越小,节点越有可能在接下来的搜索中被探索。
通过构建一个优先队列,A*算法每次从未探索的节点中选择f值最小的节点进行扩展,直至找到目标节点或遍历完整个搜索空间。
现在我们可以开始用C++实现A*算法,基于这个背景编写代码。(先把代码放上来)
#include <iostream>
#include <vector>
#include <queue>
#include <cmath>
#include <cstring>
#include <unordered_set>
using namespace std;
#define ROWS 7 // 地图行数
#define COLS 7 // 地图列数
#define ZXDJ 10 // 正交方向移动代价
#define XXDJ 14 // 对角线方向移动代价
// 枚举方向
enum dirent {
p_up, p_down, p_left, p_right,
p_lup, p_ldown, p_rdown, p_rup
};
// 表示坐标的结构体
struct MyPoint {
int row, col; // 行和列
int f, g, h; // A* 算法中的 f = g + h
bool operator==(const MyPoint &other) const {
return row == other.row && col == other.col;
}
};
// 哈希函数,用于在 unordered_set 中使用 MyPoint 作为键
struct MyPointHash {
size_t operator()(const MyPoint &p) const {
return p.row * 31 + p.col; // 简单的哈希函数
}
};
// 树节点结构体,用于存储节点位置和父节点
struct treeNode {
MyPoint pos; // 节点位置
treeNode *pParent; // 指向父节点的指针
};
// 比较函数,优先队列中比较 f 值大小
struct compare {
bool operator()(treeNode* a, treeNode* b) {
return a->pos.f > b->pos.f; // 小顶堆,f 值小的优先
}
};
// 创建树节点函数
treeNode* createTreeNode(int row, int col) {
treeNode* pNew = new treeNode; // 动态分配内存
memset(pNew, 0, sizeof(treeNode)); // 清空结构体
pNew->pos.row = row;
pNew->pos.col = col;
return pNew;
}
// 计算 H 值(曼哈顿距离)
int getH(MyPoint pos, MyPoint endpos) {
// 曼哈顿距离公式:|x1 - x2| + |y1 - y2|
return ZXDJ * (abs(endpos.row - pos.row) + abs(endpos.col - pos.col));
}
int main() {
// 0 表示可通行,1 表示障碍物
int map[ROWS][COLS] = {
{0,0,0,0,0,0,0},
{0,0,0,0,1,0,0},
{0,0,0,0,1,0,0},
{0,0,0,0,1,0,0},
{0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,},
{0,0,0,0,0,0,0},
};
MyPoint beginpos = { 2, 2, 0, 0, 0 }; // 起点
MyPoint endpos = { 2, 6, 0, 0, 0 }; // 终点
// openList: 优先队列存储待处理节点,按照 f 值排序
priority_queue<treeNode*, vector<treeNode*>, compare> openList;
// closedList: 哈希集合,存储已访问的节点,避免重复处理
unordered_set<MyPoint, MyPointHash> closedList;
// 初始化起点节点,设置 h 和 f 值
treeNode* pRoot = createTreeNode(beginpos.row, beginpos.col);
pRoot->pos.h = getH(beginpos, endpos); // 计算起点到终点的 h 值
pRoot->pos.f = pRoot->pos.h; // 起点的 f = g + h,其中 g = 0
openList.push(pRoot); // 将起点放入 openList
bool isFindend = false; // 标记是否找到终点
treeNode* pCurrent = nullptr; // 当前处理的节点
// A* 算法主循环
while (!openList.empty()) {
// 从 openList 中取出 f 值最小的节点
pCurrent = openList.top();
openList.pop();
// 如果到达终点,退出循环
if (pCurrent->pos.row == endpos.row && pCurrent->pos.col == endpos.col) {
isFindend = true;
break;
}
// 将当前节点加入 closedList
closedList.insert(pCurrent->pos);
// 遍历 8 个方向的邻居节点
for (int i = 0; i < 8; ++i) {
int newRow = pCurrent->pos.row;
int newCol = pCurrent->pos.col;
int newG = pCurrent->pos.g; // 继承父节点的 g 值
// 根据不同方向更新坐标和移动代价
switch (i) {
case p_up: newRow--; newG += ZXDJ; break;
case p_down: newRow++; newG += ZXDJ; break;
case p_left: newCol--; newG += ZXDJ; break;
case p_right: newCol++; newG += ZXDJ; break;
case p_lup: newRow--; newCol--; newG += XXDJ; break;
case p_ldown: newRow++; newCol--; newG += XXDJ; break;
case p_rdown: newRow++; newCol++