算法学习——A*搜索算法

时间:2025-03-30 07:53:10
#include <> #include <> #include <iostream> #include <vector> using namespace std; #define MAP_WIDTH 11 // 图宽 (1 pixel block) #define MAP_HEIGHT 9 // 图高 (1 pixel block) #define straight_cost 10 // 直线代价 #define diag_cost 14 // 斜线代价 typedef struct { int8_t row; int8_t col; uint16_t f; uint16_t g; uint16_t h; }point_t; //树的节点类型 struct treeNode // 结构体可以定义自身类型的指针(指针变量大小可以确定,而定义自身类型的成员则不行,因为编译时成员存储空间大小不确定) { point_t pos; // 当前点坐标 struct treeNode* pParent; // 存储当前点的父节点的指针变量 }; const uint8_t map[MAP_HEIGHT][MAP_WIDTH] = { {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,}, {0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0,}, {0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,}, {0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0,}, {0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0,}, {0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 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, 1, 0, 0, 0, 0, 0,}, }; // 2 辅助地图->标记已走过的点(封闭列表) false: 没有走过 true: 已走过 bool closeList[MAP_HEIGHT][MAP_WIDTH] = { false }; // 3 起点 终点 point_t start_pos = { 2, 2 }; point_t end_pos = { 4, 8 }; enum dircet { up, down, left, right, lup, ldown, rup, rdown }; // 计算预估代价H uint16_t getH(point_t end_pos, point_t current_pos) { uint16_t x = abs(end_pos.col - current_pos.col); uint16_t y = abs(end_pos.row - current_pos.row); return (x + y) * straight_cost; } bool isAddOpenList(point_t pos, const uint8_t(*pMap)[MAP_WIDTH], bool(*pCloseList)[MAP_WIDTH]) { if (pos.row >= MAP_HEIGHT || pos.row < 0 || pos.col >= MAP_WIDTH || pos.col < 0) // 越界 return false; if (1 == pMap[pos.row][pos.col]) //! 障碍物 return false; if (true == pCloseList[pos.row][pos.col]) //已走过 return false; return true; } bool isFindEnd = false; int main() { //4 标记起点走过 closeList[start_pos.row][start_pos.col] = true; //5 创建一颗树,树的根节点是起点 treeNode* pRoot = new treeNode; //新节点是起点 pRoot->pos = start_pos; //6 用一个动态数组存储用来比较的节点(开放列表) vector<treeNode*> openList; //7 寻路 treeNode* pCurrent = pRoot; treeNode* pChild = NULL; vector<treeNode*>::iterator it; vector<treeNode*>::iterator itMin; while (1) { //7.1 找到当前点周围能走的点 for (uint8_t i = 0; i < 8; i++) { pChild = new treeNode; pChild->pos = pCurrent->pos; switch (i) { case up: pChild->pos.row--; pChild->pos.g += straight_cost; break; case down: pChild->pos.row++; pChild->pos.g += straight_cost; break; case dircet::left: pChild->pos.col--; pChild->pos.g += straight_cost; break; case dircet::right: pChild->pos.col++; pChild->pos.g += straight_cost; break; case lup: pChild->pos.row--; pChild->pos.col--; pChild->pos.g += diag_cost; break; case ldown: pChild->pos.row++; pChild->pos.col--; pChild->pos.g += diag_cost; break; case rup: pChild->pos.row--; pChild->pos.col++; pChild->pos.g += diag_cost; break; case rdown: pChild->pos.row++; pChild->pos.col++; pChild->pos.g += diag_cost; break; default: break; } //7.2 计算 g h f 值 pChild->pos.h = getH(end_pos, pChild->pos); pChild->pos.f = pChild->pos.g + pChild->pos.h; //7.3 入树,入开放列表,标记走过 if (isAddOpenList(pChild->pos, map, closeList)) // 判断是否满足入树条件 { pChild->pParent = pCurrent; //父指针指向当前点 //入开放列表(open_list) openList.push_back(pChild); //标记已走过 closeList[pChild->pos.row][pChild->pos.col] = true; } else { delete pChild; } } if (openList.empty()) //! 如果开放列表为空,停止搜索(不会此条件遇到死路时,一直卡在循环不断开辟堆区空间造成内存溢出) break; //7.4 从开放列表中找到f值最小的节点 itMin = openList.begin(); for (it = openList.begin(); it != openList.end(); it++) { itMin = ((*itMin)->pos.f > (*it)->pos.f) ? it : itMin; } //7.5 然后变为当前点,再从开放列表中删掉 pCurrent = *itMin; openList.erase(itMin); //7.6 判断寻路结束 if (pCurrent->pos.col == end_pos.col && pCurrent->pos.row == end_pos.row) { isFindEnd = true; break; } } if (isFindEnd == true) { printf("找到终点了\n"); while (pCurrent) { printf("(%d,%d)", (int)pCurrent->pos.row, (int)pCurrent->pos.col); if (pCurrent->pos.row == start_pos.row && pCurrent->pos.col == start_pos.col) break; pCurrent = pCurrent->pParent; // 通过父指针回溯根节点(起点父指针为空) } } else printf("没有找到终点\n"); delete pRoot; system("pause"); return 0; }