当前位置:   article > 正文

❤️详解「 A*」算法原理及其算法实现(C/C++描述)_a*算法实现

a*算法实现

目录

定义和概念

原理步骤

算法推演

算法源码


定义和概念

A*算法,A*(A-Star)算法是一种静态路网中求解最短路径最有效的直接搜索方法,也是解决许多搜索问题的有效算法。算法中的距离估算值与实际值越接近,最终搜索速度越快(百度百科)

百科百科将A*算法定义为求解最短路径,我认为不够严谨。

A*算法较之传统的路径规划算法,实时性更高、灵活性更强,寻路结果更加接近人工选择的路径结果. A*寻路算法 并不是找到最优路径,只是找到 相对近的路径,因为找最优要把所有可行路径都找出来进行对比,消耗性能太大, 寻路效果只要相对近路径就行了
也因此在静态路网的寻路问题中A*算法被大量运用。
A*算法重要的三个指标 G、H、 F
G 表示从起点移动到终点的移动距离
H 表示从指定的地点移动到终点的预计移动距离
F = G + H ,F 即表示从起点经过此点预计到终点的总移动距离

距离有两个指标:

曼哈顿距离:两个点在标准坐标系上的绝对轴距总和。计算公式:|x1-x2|+|y1-y2|

欧式距离:两个点的直线距离 。计算公式: 

原理步骤

A*算法首先定义两个重要的链表:openList、closeList

通过循环将可能到达的结点加入openList,已经走过的结点加入closeList

1)动态展示

2)静态展示

1. 从起点开始, 把它作为待处理的方格存入一个预测可达的节点列表,简称 openList, 即把起点放入“预测可达节点列表”, 可达节点列表 openList 就是一个等待检查方格的列表。
2. 寻找 openList 中 F 值最小的点 min(一开始只有起点)周围可以到达的方格(可到达的意思是其不是障碍物,也不存 在关闭列表中的方格,即不是已走过的方格)。计算 min 周围可到达的方格的 F 值。将还没在 openList 中点放入其中, 并 设置它们的"父方格"为点 min,表示他们的上一步是经过 min 到达的。如果 min 下一步某个可到达的方格已经在 openList 列表那么并且经 min 点它的 F 值更优,则修改 F 值并把其"父方格"设为点 min。
3. 把 2 中的点 min 从"开启列表"中删除并存入"关闭列表"closeList 中, closeList 中存放的都是不需要再次检查的方格。如 果 2 中点 min 不是终点并且开启列表的数量大于零,那么继续从第 2 步开始。如果是终点执行第 4 步,如果openList 列表数量为零,那么就是找不到有效路径。
4.如果第 3 步中 min 是终点,则结束查找,直接追溯父节点到起点的路径即为所选路径。

算法推演

1)二维图中结点数据结构可定义为:

  1. typedef struct _Point
  2. {
  3. int x, y;
  4. int F, G, H;//F=G+H
  5. struct _Point *parent;
  6. }Point;

2)找出目标结点

  1. static Point *FindPath(Point *startPoint, Point *endPoint)
  2. {
  3. openList.push_back(AllocPoint(startPoint->x,startPoint->y));
  4. while (!openList.empty())
  5. {
  6. //1.第一步 取openlist中的F最小值
  7. Point *curPoint = GetLeastPoint();
  8. //2.将当前结点加入到closelist中
  9. openList.remove(curPoint);
  10. closeList.push_back(curPoint);
  11. //3.找到当前结点周围可达的节点 并计算F值
  12. vector<Point *>surroundPoints = GetSurroundPoints(curPoint);
  13. for (vector<Point *>::const_iterator it= surroundPoints.begin();it!= surroundPoints.end();it++)
  14. {
  15. Point *target = *it;
  16. Point *exsit = isInList(openList, target);
  17. if (!exsit)//如果可达结点不在openList中,则直接加入openList链表
  18. {
  19. target->parent = curPoint;
  20. target->G = calcDistance(curPoint, target);
  21. target->H = calcDistance(target, endPoint);
  22. target->F = target->G + target->H;
  23. openList.push_back(target);
  24. }
  25. else
  26. //如果可达结点已经在openList中,则重新计算F值,如果小于原F值,则改变其父节点为当前结点,G、F
  27. //值随之改变
  28. {
  29. int tmpG = calcDistance(curPoint, target);
  30. if (tmpG<target->G)
  31. {
  32. exsit->parent = curPoint;
  33. exsit->G = tmpG;
  34. exsit->F = tmpG + exsit->H;
  35. }
  36. delete target;
  37. }
  38. }
  39. surroundPoints.clear();
  40. Point *resPoint = isInList(openList, endPoint);
  41. if (resPoint)
  42. return resPoint;
  43. }
  44. }

3)通过目标结点的父节遍历链表找到开始结点,以获得正确路径

  1. /*返回正确路径*/
  2. list<Point*> GetPath(Point *startPoint, Point *endPoint)
  3. {
  4. Point *result = FindPath(startPoint, endPoint);
  5. list<Point*> path;
  6. //返回路径,如果没有找到路径则返回空链表
  7. while (result)
  8. {
  9. path.push_front(result);
  10. result = result->parent;
  11. }
  12. return path;
  13. }

 算法源码

 运行截图:

由此也可知,A*算法所得结果并非最短路径

AStar.h

  1. #pragma once
  2. #include<list>
  3. #include<vector>
  4. using namespace std;
  5. const int kCost1 = 10;//直移一格消耗
  6. const int kCost2 = 14;//斜移一格消耗
  7. typedef struct _Point
  8. {
  9. int x, y;
  10. int F, G, H;//F=G+H
  11. struct _Point *parent;
  12. }Point;
  13. /*分配一个格子*/
  14. Point *AllocPoint(int x, int y);
  15. /*初始化地图*/
  16. void InitAstarMaze(int *Maze, int lines, int colums);
  17. /*A*算法寻找路径*/
  18. list<Point*> GetPath(Point *startPoint, Point *endPoint);
  19. /*清理资源*/
  20. void ClearAstarMaze();

AStar.cpp

  1. #include<math.h>
  2. #include"AStar.h"
  3. #include <iostream>
  4. #include <vector>
  5. static int *maze;//地图
  6. static int cols;//列数
  7. static int lines;//行数
  8. static list<Point*>openList;
  9. static list<Point*>closeList;
  10. /*A*算法寻找路径*/
  11. Point * isInList(const list<Point *> point, const Point *target);
  12. static Point *GetLeastPoint();//找出openlist中F值最小的节点
  13. static vector<Point*> GetSurroundPoints(const Point *point);//找到当前结点周围可达的节点
  14. bool isCanreach(const Point *point, const Point *target);//判断这两点是否可达
  15. int calcDistance(Point *target, Point *endPoint);
  16. static Point *FindPath(Point *startPoint, Point *endPoint)
  17. {
  18. openList.push_back(AllocPoint(startPoint->x,startPoint->y));
  19. while (!openList.empty())
  20. {
  21. //1.第一步 取openlist中的F最小值
  22. Point *curPoint = GetLeastPoint();
  23. //2.将当前结点加入到closelist中
  24. openList.remove(curPoint);
  25. closeList.push_back(curPoint);
  26. //3.找到当前结点周围可达的节点 并计算F值
  27. vector<Point *>surroundPoints = GetSurroundPoints(curPoint);
  28. for (vector<Point *>::const_iterator it= surroundPoints.begin();it!= surroundPoints.end();it++)
  29. {
  30. Point *target = *it;
  31. Point *exsit = isInList(openList, target);
  32. if (!exsit)
  33. {
  34. target->parent = curPoint;
  35. target->G = calcDistance(curPoint, target);
  36. target->H = calcDistance(target, endPoint);
  37. target->F = target->G + target->H;
  38. openList.push_back(target);
  39. }
  40. else
  41. {
  42. int tmpG = calcDistance(curPoint, target);
  43. if (tmpG<target->G)
  44. {
  45. exsit->parent = curPoint;
  46. exsit->G = tmpG;
  47. exsit->F = tmpG + exsit->H;
  48. }
  49. delete target;
  50. }
  51. }
  52. surroundPoints.clear();
  53. Point *resPoint = isInList(openList, endPoint);
  54. if (resPoint)
  55. return resPoint;
  56. }
  57. }
  58. void InitAstarMaze(int *arr,int _lines, int colums)
  59. {
  60. maze = arr;
  61. cols = colums;
  62. lines = _lines;
  63. }
  64. Point * AllocPoint(int x, int y)
  65. {
  66. Point * tmp = new Point;
  67. memset(tmp, 0, sizeof(Point));
  68. tmp->x = x;
  69. tmp->y = y;
  70. return tmp;
  71. }
  72. /*返回正确路径*/
  73. list<Point*> GetPath(Point *startPoint, Point *endPoint)
  74. {
  75. Point *result = FindPath(startPoint, endPoint);
  76. list<Point*> path;
  77. //返回路径,如果没有找到路径则返回空链表
  78. while (result)
  79. {
  80. path.push_front(result);
  81. result = result->parent;
  82. }
  83. return path;
  84. }
  85. static Point *GetLeastPoint()
  86. {
  87. Point *resPoint = openList.front();
  88. if (!openList.empty())
  89. {
  90. for (list<Point *>::const_iterator it= openList.begin();it!=openList.end();it++)
  91. if ((*it)->F < resPoint->F)
  92. {
  93. resPoint = *it;
  94. }
  95. }
  96. return resPoint;
  97. }
  98. static vector<Point*> GetSurroundPoints(const Point *point)
  99. {
  100. vector<Point *> surroundPoints;
  101. for (int x= point->x-1;x<= point->x+1;x++)
  102. for (int y = point->y - 1; y <= point->x+1; y++)
  103. {
  104. Point *tmp = AllocPoint(x, y);
  105. if (isCanreach(point,tmp))
  106. {
  107. surroundPoints.push_back(tmp);
  108. }
  109. else
  110. {
  111. delete tmp;
  112. }
  113. }
  114. return surroundPoints;
  115. }
  116. Point * isInList(const list<Point *> point,const Point *target)
  117. {
  118. for (list<Point *>::const_iterator it = point.begin(); it != point.end(); it++)
  119. {
  120. if ((*it)->x==target->x && (*it)->y==target->y)
  121. {
  122. return *it;
  123. }
  124. }
  125. return NULL;
  126. }
  127. bool isCanreach(const Point *point, const Point *target)
  128. {
  129. if (target->x<0|| target->x>(lines-1)
  130. || target->y<0|| target->y>(cols-1)
  131. || maze[target->x*cols+target->y]==1//1代表无法走的格子
  132. || maze[target->x*cols + target->y] == 2//2代表无法走的格子
  133. || (target->x==point->x && target->y==point->y)
  134. || isInList(closeList,target)!=NULL)
  135. {
  136. return false;
  137. }
  138. if (abs(point->x - target->x) + abs(point->y - target->y) == 1)
  139. return true;
  140. else
  141. return false;
  142. }
  143. int calcDistance(Point *target, Point *endPoint)
  144. {
  145. return abs(target->x - endPoint->x) + abs(target->y - endPoint->y);
  146. }
  147. void ClearAstarMaze()
  148. {
  149. maze = NULL;
  150. lines = cols = 0;
  151. for (list<Point *>::iterator it=openList.begin();it!=openList.end();)
  152. {
  153. delete *it;
  154. it = openList.erase(it);
  155. }
  156. for (list<Point *>::iterator it = closeList.begin(); it != closeList.end();)
  157. {
  158. delete *it;
  159. it = closeList.erase(it);
  160. }
  161. }

main.cpp

  1. #include <iostream>
  2. #include "AStar.h"
  3. #include<windows.h>
  4. int main()
  5. {
  6. int map[13][13] = {
  7. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
  8. { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, },
  9. { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, },
  10. { 0, 1, 0, 1, 0, 1, 2, 1, 0, 1, 0, 1, 0, },
  11. { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, },
  12. { 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, },
  13. { 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, },
  14. { 2, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 2, },
  15. { 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, },
  16. { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, },
  17. { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, },
  18. { 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, },
  19. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } };
  20. InitAstarMaze(&map[0][0], 13, 13);
  21. Point *start = AllocPoint(12, 12);
  22. Point *end = AllocPoint(0, 0);
  23. list <Point*> path = GetPath(start, end);
  24. for (list<Point*>::iterator it = path.begin(); it != path.end(); it++)
  25. {
  26. Point *res = *it;
  27. cout << "(" << res->x << "," << res->y << ")" << endl;
  28. Sleep(800);
  29. }
  30. ClearAstarMaze();
  31. }

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号