详细说明如何使用C++编写A*算法

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++
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值