基于C++实现的A*算法
-
AStar算法相对于Dijkstra算法而言升级的地方在于引入了启发距离,即H(当前点到终点的预计距离),因此在每次大循环中Dijkstra算法找的最短距离仅仅是G(起点到当前点的距离),而AStar算法找的是(G+H)即F的最小值,因此AStar算法可以更快的找到终点,从而在判断两点最短路径时候有着更快的结束时间即更高的效率
-
这两种算法本质上而言均是找起点到每一个点的最短距离,而AStar算法好就好在它引入了每次对终点的度量因而可以比Dijkstra算法更快的找到对终点的距离!
其具体的原理步骤可以参见其他优秀的blog如:A* 寻路算法 - christanxw的专栏 - C++博客
基于c++的链表的A*算法代码如下:
AStar.h文件
#pragma once
#include<vector>
#include<list>
#include<memory>
#include<algorithm>
#include<iostream>
struct ANode
{
ANode(int X, int Y, std::shared_ptr<ANode> p = nullptr) : x(X), y(Y), prev(p) {}
int x; //点的x坐标
int y; //点的y坐标
int G=0; //起点到该点的欧拉距离
int H=0;//该点到终点的曼哈顿距离
int F=0;//G+H
std::weak_ptr<ANode> prev;//指向的前一个节点!!!改成了weak_ptr不然数据多的时候析构报错
};
class AStar
{
public:
AStar(std::vector<std::vector<int>> m ): maps(m) {}
std::shared_ptr<ANode> findPath(std::shared_ptr<ANode> beg, std::shared_ptr<ANode> end);
void PrintAStarPath(const std::pair<int, int> &, const std::pair<int, int> &);
~AStar()
{
openlist.clear();
closeist.clear();
}
private:
void refreshOpenList(std::shared_ptr<ANode>, std::shared_ptr<ANode> end);
int calculateH(std::shared_ptr<ANode>, std::shared_ptr<ANode>) const;
int calculateF(std::shared_ptr<ANode>,std::shared_ptr<ANode>) const;
private:
std::vector<std::vector<int>> maps;//地图
std::list<std::shared_ptr<ANode>> openlist;//保存还未遍历过的节点
std::list<std::shared_ptr<ANode>> closeist;//保存已经找到最短路径的节点
const static int costLow;//上下位移的距离
const static int costHigh;//斜向位移的距离
};
const int AStar::costLow = 10;
const int AStar::costHigh = 14;
int AStar::calculateH(std::shared_ptr<ANode> point, std::shared_ptr<ANode> end) const
{
return costLow * (std::abs(point->x - end->x) + std::abs(point->y - end->y));
}
int AStar::calculateF(std::shared_ptr<ANode> point,std::shared_ptr<ANode> end) const
{
return point->G + calculateH(point, end);
}
std::shared_ptr<ANode> AStar::findPath(std::shared_ptr<ANode> beg, std::shared_ptr<ANode> end)
{
refreshOpenList(beg,end);
while (!openlist.empty())
{
auto iter = std::min_element(openlist.cbegin(), openlist.cend(), [](std::shared_ptr<ANode> p1, std::shared_ptr<ANode> p2)
{ return p1->F <= p2->F;});
closeist.push_back(*iter);
std::shared_ptr<ANode> iter_temp = *iter;
openlist.erase(iter);
refreshOpenList(iter_temp, end);
auto iter2 = std::find_if(openlist.cbegin(), openlist.cend(), [end](std::shared_ptr<ANode> sp)
{ return (sp->x == end->x) && (sp->y == end->y); });
if (iter2 != openlist.end())
return *iter2;
}
return nullptr;
}
void AStar::refreshOpenList(std::shared_ptr<ANode> point, std::shared_ptr<ANode> end)
{
bool upIsWall = false;//表示当前点上有障碍物,即对应的斜向没法走
bool downIsWall = false;
bool leftIsWall = false;
bool rightIsWall = false;
if (point->x - 1 >= 0 && maps[point->x - 1][point->y] == 1)
upIsWall = true;
if (point->x + 1 < int(maps.size()) && maps[point->x + 1][point->y] == 1)
downIsWall = true;
if (point->y - 1 >= 0 && maps[point->x][po