前言

复习下寻路相关的东西,而且A star寻路在游戏开发中应用挺多的,故记录下。

正文

迪杰斯特拉算法

说起A*得先谈谈Dijkstra算法,它是在BFS基础上的一种带权值的两点最短寻路贪心算法。

算法步骤

0.初始化图,输入起点,将所有点到起始点的距离设置为∞。

1.将起始点OriginNode记录为已访问,并从OriginNode开始将周围的点加入到待遍历列表中,更新到达这些点的距离,并将他们的父节点设置为起始点OriginNode。

2.如果待遍历列表不为空,则从列表中取出到达距离最小的点currentNode;反之则跳到第5步。

3.遍历currentNode邻接的点neighbors:

1)  如果已访问过,则遍历其他点。

2) 如果邻接的某点neighbor已经在待遍历列表中,则比较neighbor当前的距离distance(OriginNode,neighbor) 与  distance(OriginNode,currentNode) + distance(currentNode,neighbor), 如果后者更小,则将neighbor的距离值更新为该值并将父节点设置为currentNode。

3) 如果不在待遍历列表,则将neighbor放入待遍历列表,并则将neighbor的距离值更新为  distance(OriginNode,currentNode) + distance(currentNode,neighbor), 并将父节点设置为currentNode。

4.重复第2步

5.输入终点,从终点开始回溯父节点,打印路径。

动态过程

A* 寻路算法

A*的思路其实与Dijkstra一致,相比较Dijkstra,A*引入了一个启发公式来衡量消耗

其中 g(n) 代表从起始点到当前点的消耗,h(n) 代表终点到当前点的预估消耗(通常用曼哈顿距离或者欧拉距离衡量,这里不赘述,参考)。

算法思路

  1. /*
  2. A*寻路算法
  3.  
  4. 带权值的BFS
  5. 每个点保存达到该点的消耗F = G值(出发点到当前点的代价值) + H值(目标点到当前点的预估距离,常用曼哈顿距离或者欧拉距离)
  6. 维护着两个列表,开放列表和关闭列表
  7.  
  8. 逻辑:
  9. 初始化列表Close,Open,Path,将StartNode放入Open列表中
  10. while(true)
  11. {
  12. 从Open表中取得F值最小的节点CurrentNode.
  13. 从Open表中删除CurrentNode
  14. 将CurrentNode加入Close表中
  15. if ( CurrentNode 是 目标点targetNode)
  16. {
  17. 从CurrentNode点回溯直到起点并将所有回溯的节点加入Path表
  18. 打印Path表
  19. return;
  20. }
  21. for (CurrentNode 的每一个邻接点 neighbor)
  22. {
  23. if(neighbor 在 Close表中 || neighbor 不可通行)
  24. {
  25. continue;
  26. }
  27. if(neighbor 在 Open表中)
  28. {
  29. if( CurrentNode 到达neighbor的消耗costG + node的G值 < neighbor的G值)
  30. {
  31. 更新neighbor的G值;
  32. 将neighbor的回溯节点fatherNode设置为CurrentNode;
  33. }
  34. }
  35. else
  36. {
  37. 更新neighbor的G值;
  38. 更新neighbor的H值;
  39. 将neighbor的回溯节点fatherNode设置为CurrentNode;
  40. 将neighbor放入Open列表;
  41. }
  42. }
  43. }
  44. */

动态过程

代码:

AstarNode的定义实现.

Astar.h

  1. #pragma once
  2. #include <vector>
  3. #include <math.h>
  4.  
  5. using std::vector;
  6.  
  7. class AstarNode
  8. {
  9. private:
  10. int m_igValue;
  11. int m_ihValue;
  12. int m_ifValue;
  13. AstarNode* m_father;
  14. public:
  15. int x;
  16. int y;
  17. bool isPass;
  18. public:
  19. void SetG(int iValue);
  20. int GetG() const;
  21. int GetH() const;
  22. int GetF() const;
  23. void CalculateH(const AstarNode* endNode);
  24. void SetFather(AstarNode* node);
  25. AstarNode* GetFather() const;
  26. bool isInList(const vector<AstarNode*>& nodeList) const;
  27. public:
  28. AstarNode();
  29. AstarNode(int x,int y);
  30. AstarNode(const AstarNode& node);
  31. ~AstarNode();
  32. AstarNode& operator=(const AstarNode& node);
  33. };

Astar.cpp

  1. #include "Astar.h"
  2.  
  3. AstarNode::AstarNode()
  4. {
  5. isPass = true;
  6. m_igValue = 0;
  7. m_ihValue = 0;
  8. m_ifValue = 0;
  9. m_father = nullptr;
  10. }
  11.  
  12. AstarNode::AstarNode(int x,int y)
  13. {
  14. isPass = true;
  15. m_igValue = 0;
  16. m_ihValue = 0;
  17. m_ifValue = 0;
  18. m_father = nullptr;
  19. this->x = x;
  20. this->y = y;
  21. }
  22.  
  23. AstarNode::AstarNode(const AstarNode& node)
  24. {
  25. isPass = node.isPass;
  26. m_igValue = node.GetG();
  27. m_ihValue = node.GetH();
  28. m_ifValue = node.GetF();
  29. m_father = node.GetFather();
  30. this->x = node.x;
  31. this->y = node.y;
  32. }
  33.  
  34. AstarNode& AstarNode::operator=(const AstarNode& node)
  35. {
  36. isPass = node.isPass;
  37. m_igValue = node.GetG();
  38. m_ihValue = node.GetH();
  39. m_ifValue = node.GetF();
  40. m_father = node.GetFather();
  41. this->x = node.x;
  42. this->y = node.y;
  43. return *this;
  44. }
  45.  
  46. AstarNode::~AstarNode()
  47. {
  48.  
  49. }
  50.  
  51. void AstarNode::SetG(int iValue)
  52. {
  53. m_igValue = iValue;
  54. }
  55.  
  56. int AstarNode::GetG() const
  57. {
  58. return m_igValue;
  59. }
  60.  
  61. int AstarNode::GetF() const
  62. {
  63. return m_igValue + m_ihValue;
  64. }
  65.  
  66. int AstarNode::GetH() const
  67. {
  68. return m_ihValue;
  69. }
  70.  
  71. void AstarNode::CalculateH(const AstarNode* endNode)
  72. {
  73. m_ihValue = abs(endNode->x - x) + abs(endNode->y - y);
  74. }
  75.  
  76. void AstarNode::SetFather(AstarNode* node)
  77. {
  78. m_father = node;
  79. }
  80.  
  81. AstarNode* AstarNode::GetFather() const
  82. {
  83. return m_father;
  84. }
  85.  
  86. bool AstarNode::isInList(const vector<AstarNode*>& nodeList) const
  87. {
  88. for(auto iter = nodeList.begin();iter != nodeList.end();iter++)
  89. {
  90. if((*iter)->x == this->x && (*iter)->y == this->y)
  91. return true;
  92. }
  93. return false;
  94. }

main.cpp

  1. #include "Astar.cpp"
  2. #include <algorithm>
  3. using namespace std;
  4.  
  5. /*
  6. 'e' 终点
  7. 's' 起点
  8. '#' 障碍物
  9. '-' 可通行点
  10. 'o' 回溯路径节点
  11. */
  12.  
  13. vector<vector<char>> graph = {
  14. {'-', '-', '-', '-', '-', '-', '-'},
  15. {'-', '-', 'e', '#', '-', '-', '-'},
  16. {'-', '#', '#', '#', '#', '-', '-'},
  17. {'-', '-', '-', '-', '#', '#', '-'},
  18. {'-', '-', '#', '-', '#', '-', '-'},
  19. {'-', '-', '-', '#', '-', '-', '-'},
  20. {'-', '-', '-', '-', '-', '-', 's'},
  21. };
  22.  
  23. void BuildGraph(vector<vector<AstarNode *>> &astarGraph, AstarNode &start, AstarNode &end)
  24. {
  25. for (int i = 0; i < astarGraph.size(); i++)
  26. {
  27. auto row = astarGraph[i];
  28. for (int j = 0; j < row.size(); j++)
  29. {
  30. char mark = graph[i][j];
  31. if (mark == 's')
  32. {
  33. start.x = i;
  34. start.y = j;
  35. start.SetG(0);
  36. start.CalculateH(&end);
  37. astarGraph[i][j] = &start;
  38. }
  39. else if (mark == 'e')
  40. {
  41. end.x = i;
  42. end.y = j;
  43. astarGraph[i][j] = &end;
  44. }
  45. else if (mark == '#')
  46. {
  47. astarGraph[i][j] = new AstarNode(i, j);
  48. astarGraph[i][j]->isPass = false;
  49. }
  50. else
  51. {
  52. astarGraph[i][j] = new AstarNode(i, j);
  53. }
  54. }
  55. }
  56. }
  57.  
  58. void printGraph()
  59. {
  60. for (int i = 0; i < graph.size(); i++)
  61. {
  62. auto line = graph[i];
  63. for (int j = 0; j < line.size(); j++)
  64. {
  65. cout << line[j] << " ";
  66. }
  67. cout << endl;
  68. }
  69. }
  70.  
  71. vector<AstarNode *>::iterator GetMinFNode(vector<AstarNode *> &openList)
  72. {
  73. auto tmp = openList.begin();
  74. for (auto iter = openList.begin(); iter != openList.end(); iter++)
  75. {
  76. if ((*iter)->GetF() < (*tmp)->GetF())
  77. {
  78. tmp = iter;
  79. }
  80. }
  81. return tmp;
  82. }
  83.  
  84. inline int GetCost(int xDiff, int yDiff)
  85. {
  86. if (xDiff == 0 || yDiff == 0)
  87. return 10;
  88. return 14;
  89. }
  90.  
  91. void SearchOneNode(AstarNode &currentNode, AstarNode &neighbor, AstarNode &startNode, AstarNode &endNode, vector<AstarNode *> &openList, vector<AstarNode *> &closeList)
  92. {
  93. if (neighbor.isInList(closeList) || !neighbor.isPass)
  94. return;
  95. int gCost = GetCost(currentNode.x - neighbor.x, currentNode.y - neighbor.y);
  96. if (neighbor.isInList(openList))
  97. {
  98. if (currentNode.GetG() + gCost < neighbor.GetG())
  99. {
  100. neighbor.SetG(currentNode.GetG() + gCost);
  101. neighbor.SetFather(&currentNode);
  102. }
  103. }
  104. else
  105. {
  106. neighbor.SetG(currentNode.GetG() + gCost);
  107. neighbor.SetFather(&currentNode);
  108. neighbor.CalculateH(&endNode);
  109. openList.push_back(&neighbor);
  110. }
  111. }
  112.  
  113. void Astar()
  114. {
  115. vector<AstarNode *> OpenList;
  116. vector<AstarNode *> CloseList;
  117. vector<AstarNode *> Path;
  118. size_t len = graph.size();
  119. vector<vector<AstarNode *>> astarGraph(len, vector<AstarNode *>(len));
  120.  
  121. AstarNode startNode;
  122. AstarNode endNode;
  123.  
  124. BuildGraph(astarGraph, startNode, endNode);
  125. OpenList.push_back(&startNode);
  126. while (!OpenList.empty())
  127. {
  128. auto it = GetMinFNode(OpenList);
  129. AstarNode *currentNode = *it;
  130. OpenList.erase(it);
  131. CloseList.push_back(currentNode);
  132. if (currentNode->x == endNode.x && currentNode->y == endNode.y)
  133. {
  134. while (currentNode->GetFather())
  135. {
  136. graph[currentNode->x][currentNode->y] = graph[currentNode->x][currentNode->y] == '-' ? 'o' : 'e';
  137. Path.push_back(currentNode);
  138. currentNode = currentNode->GetFather();
  139. }
  140. printGraph();
  141. break;
  142. }
  143. int curX = currentNode->x;
  144. int curY = currentNode->y;
  145. int row = graph.size();
  146. int column = row;
  147. if (curX + 1 < row)
  148. SearchOneNode(*currentNode, *astarGraph[curX + 1][curY], startNode, endNode, OpenList, CloseList);
  149. if (curX - 1 >= 0)
  150. SearchOneNode(*currentNode, *astarGraph[curX - 1][curY], startNode, endNode, OpenList, CloseList);
  151. if (curY + 1 < column)
  152. SearchOneNode(*currentNode, *astarGraph[curX][curY + 1], startNode, endNode, OpenList, CloseList);
  153. if (curY - 1 >= 0)
  154. SearchOneNode(*currentNode, *astarGraph[curX][curY - 1], startNode, endNode, OpenList, CloseList);
  155. if (curX - 1 >= 0 && curY - 1 >= 0)
  156. SearchOneNode(*currentNode, *astarGraph[curX - 1][curY - 1], startNode, endNode, OpenList, CloseList);
  157. if (curX - 1 >= 0 && curY + 1 < column)
  158. SearchOneNode(*currentNode, *astarGraph[curX - 1][curY + 1], startNode, endNode, OpenList, CloseList);
  159. if (curX + 1 < row && curY - 1 >= 0)
  160. SearchOneNode(*currentNode, *astarGraph[curX + 1][curY - 1], startNode, endNode, OpenList, CloseList);
  161. if (curX + 1 < row && curY + 1 < row)
  162. SearchOneNode(*currentNode, *astarGraph[curX + 1][curY + 1], startNode, endNode, OpenList, CloseList);
  163. }
  164. cout << endl;
  165. }
  166.  
  167. int main()
  168. {
  169. auto start = chrono::steady_clock::now();
  170. Astar();
  171. auto end = chrono::steady_clock::now();
  172. cout << chrono::duration<double, milli>(end - start).count() << " ms" << endl;
  173. getchar();
  174. }

参考资料

A* 搜索算法(Python )     作者: 漫步_9378

 
 
 

数据结构和算法总结(三):A* 寻路算法的更多相关文章

  1. 【数据结构】 最小生成树(三)——prim算法

    上一期介绍到了kruskal算法,这个算法诞生于1956年,重难点就是如何判断是否形成回路,此处要用到并查集,不会用当然会觉得难,今天介绍的prim算法在kruskal算法之后一年(即1957年)诞生 ...

  2. 人工智能: 自动寻路算法实现(三、A*算法)

    博客转载自:https://blog.csdn.net/kwame211/article/details/78139506 本篇文章是机器人自动寻路算法实现的第三章.我们要讨论的是一个在一个M×N的格 ...

  3. [转] A*寻路算法C++简单实现

    参考文章: http://www.policyalmanac.org/games/aStarTutorial.htm   这是英文原文<A*入门>,最经典的讲解,有demo演示 http: ...

  4. 【数据结构】 最小生成树(二)——kruskal算法

    上一期说完了什么是最小生成树,这一期咱们来介绍求最小生成树的算法:kruskal算法,适用于稀疏图,也就是同样个数的节点,边越少就越快,到了数据结构与算法这个阶段了,做题靠的就是速度快,时间复杂度小. ...

  5. [A*算法]基于Unity实现A*算法(二)

    写在前面:上一篇当时是非常简单的了解一下A*,昨天还有一些问题没解决,就暂时把自己查阅的文坛摘抄了过来(毕竟人家写的比我要好的多 :> ) 今天终于解决了,就又写了这一篇,正好我自己再梳理一遍, ...

  6. 图论算法(四)Dijkstra算法

    最短路算法(三)Dijkstra算法 PS:因为这两天忙着写GTMD segment_tree,所以博客可能是seg+图论混搭着来,另外segment_tree的基本知识就懒得整理了-- Part 1 ...

  7. A*寻路算法的探寻与改良(三)

    A*寻路算法的探寻与改良(三) by:田宇轩                                        第三分:这部分内容基于树.查找算法等对A*算法的执行效率进行了改良,想了解细 ...

  8. Java数据结构和算法(三)顺序存储的树结构

    Java数据结构和算法(三)顺序存储的树结构 二叉树也可以用数组存储,可以和完全二叉树的节点一一对应. 一.树的遍历 // 二叉树保存在数组中 int[] data; public void preO ...

  9. 重读《学习JavaScript数据结构与算法-第三版》- 第4章 栈

    定场诗 金山竹影几千秋,云索高飞水自流: 万里长江飘玉带,一轮银月滚金球. 远自湖北三千里,近到江南十六州: 美景一时观不透,天缘有分画中游. 前言 本章是重读<学习JavaScript数据结构 ...

随机推荐

  1. VUE项目开发流程

    前期准备 安装npm 安装webpack\vue-cli(2.9.6版本--版本不同可能会导致以下一些目录结构以及错误解决办法不符合实际情况) 创建项目 初始化创建项目,项目名称.项目描述.拥有者等等 ...

  2. ICEM—二维混合网格对齐节点

    原视频下载地址: https://pan.baidu.com/s/1bpnjfT9 密码: jeuv

  3. Kinect v1 (Microsoft Kinect for Windows v1 )彩色和深度图像对的采集步骤

    Kinect v1 (Microsoft Kinect for Windows v1 )彩色和深度图像对的采集步骤 一.在ubuntu下尝试 1. 在虚拟机VWware Workstation 12. ...

  4. WINRAR弹窗堆栈

    0:000> db 004ddfa8004ddfa8 6f 00 70 00 65 00 6e 00-00 00 00 00 2d 00 6e 00 o.p.e.n.....-.n. 03063 ...

  5. php-fpm(绕过open_basedir,结合ssrf)

    环境的安装->https://www.cnblogs.com/zaqzzz/p/11870489.html 1.nginx的畸形访问 因为安装的是php7.0,所以需要手动修改一下(版本低的时候 ...

  6. vue实现购物清单列表添加删除

    vue实现购物清单列表添加删除 一.总结 一句话总结: 基础的v-model操作,以及数组的添加(push)删除(splice)操作 1.checkbox可以绑定数组,也可以直接绑定值? 绑定数组就是 ...

  7. mysql安装到启动遇见的问题

    一.有时候安装mysql后使用mysql命令时报错 Can't connect to MySQL server on localhost (10061),或者用net start mysql 时报服务 ...

  8. python连接mysql数据库(MySQL)

    在介绍python在数据库中的操作之前先简单介绍点mysql中的操作语言: [root@elk-server --]# mysql -u root -p Enter password: Welcome ...

  9. Visual Studio Code 上java开发环境搭建

    在把一些开源的SDK中java代码转成C#代码时经常需要写点java代码来实验下功能,装个Eclipse或IDEAs吧,好像也不太值当,所以用vs code搭个环境偶尔来实验下.以下: 1.下载并装好 ...

  10. 相机用的 SD Card 锁Lock 烂掉了,无法正常写入

    没错,又碰到奇奇怪怪的SD Card  Lock 烂掉了 , 无法正常写入,不要急,千万不要扔了,拿起透明胶粘在 Lock 处,注意不要粘住金手指哦,再放回去就可以读写了,但是透明胶不耐摩擦,用了几次 ...