A*算法原理与实现

article/2025/4/19 4:37:01

前言

        A*算法最初发表于1968年,由Stanford研究院的Peter Hart, Nils Nilsson以及Bertram Raphael发表。它可以被认为是Dijkstra算法的扩展。

        由于借助启发函数的引导,A*算法通常拥有更好的性能。


一、

        A*吸取了Dijkstra 算法中的cost_so_far,为每个边长设置权值,不停的计算每个顶点到起始顶点的距离(G),以获得最短路线,
        同时也汲取贪婪最佳优先搜索算法中不断向目标前进优势,并持续计算每个顶点到目标顶点的距离(Heuristic distance),以引导搜索队列不断想目标逼近,从而搜索更少的顶点,保持寻路的高效。

二、原理与实现

1.启发函数

启发函数会影响A*算法的行为。

  • 在极端情况下,当启发函数h(n)始终为0,则将由g(n)决定节点的优先级,此时算法就退化成了Dijkstra算法。
  • 如果h(n)始终小于等于节点n到终点的代价,则A*算法保证一定能够找到最短路径。但是当h(n)的值越小,算法将遍历越多的节点,也就导致算法越慢。
  • 如果h(n)完全等于节点n到终点的代价,则A*算法将找到最佳路径,并且速度很快。可惜的是,并非所有场景下都能做到这一点。因为在没有达到终点之前,我们很难确切算出距离终点还有多远。
  • 如果h(n)的值比节点n到终点的代价要大,则A*算法不能保证找到最短路径,不过此时会很快。
  • 在另外一个极端情况下,如果h()n相较于g(n)大很多,则此时只有h(n)产生效果,这也就变成了最佳优先搜索。

        由上面这些信息我们可以知道,通过调节启发函数我们可以控制算法的速度和精确度。因为在一些情况,我们可能未必需要最短路径,而是希望能够尽快找到一个路径即可。这也是A*算法比较灵活的地方。

对于网格形式的图,有以下这些启发函数可以使用:

  • 如果图形中只允许朝上下左右四个方向移动,则可以使用曼哈顿距离(Manhattan distance)。
  • 如果图形中允许朝八个方向移动,则可以使用对角距离。
  • 如果图形中允许朝任何方向移动,则可以使用欧几里得距离(Euclidean distance)。

2.伪代码

把起始格添加到 "开启列表" 
do 
{ 寻找开启列表中F值最低的格子, 我们称它为当前格. 把它切换到关闭列表. 对当前格相邻的8格中的每一个 if (它不可通过 || 已经在 "关闭列表" 中) { 什么也不做. } if (它不在开启列表中) { 把它添加进 "开启列表", 把当前格作为这一格的父节点, 计算这一格的 FGH }if (它已经在开启列表中) { if (用 G 值为参考检查新的路径是否更好, 更低的G值意味着更好的路径) { 把这一格的父节点改成当前格, 并且重新计算这一格的 GF 值. } }
} while( 目标格已经在 "开启列表", 这时候路径被找到) 
如果开启列表已经空了, 说明路径不存在.最后从目标格开始, 沿着每一格的父节点移动直到回到起始格, 这就是路径.

3.代码

主循化

void Astar(const int x, const int y)
{if(x == y){plan_path.clear();plan_path.push_back(x);isfindpath = true;std::cout << "---------------------------------------------------" << std::endl;std::cout << "* find! *" << std::endl;return;}openlist.clear();closelist.clear();//放入起点openlist.push_back(x);plan_ways_map[x]->G = 0;plan_ways_map[x]->H = Calculateh(y, x);plan_ways_map[x]->F = Calculatef(x);while (!openlist.empty()){int minidnode = Findleastf(openlist);//找到F值最小的点openlist.remove(minidnode);//从开启列表中删除closelist.push_back(minidnode);//放到关闭列表//1,找到下一步待选点std::vector<int> candiates = Getnextnode(minidnode);for(int i = 0; i < candiates.size(); ++i){//2,对某一点,如果它不在开启列表中,加入到开启列表,设置当前格为其父节点,计算F G Hif(!Isinlist(candiates[i], openlist)){plan_ways_map[candiates[i]]->parent = minidnode;plan_ways_map[candiates[i]]->G = Calculateg(x, candiates[i]);plan_ways_map[candiates[i]]->H = Calculateh(y, candiates[i]);plan_ways_map[candiates[i]]->F = Calculatef(candiates[i]);openlist.push_back(candiates[i]);}else{//3,对某一点,它在开启列表中,计算G值, 如果比原来的大, 就什么都不做, 否则设置它的父节点为当前点,并更新G和Fdouble tempg = Calculateg(x, candiates[i]);if(tempg > plan_ways_map[candiates[i]]->G){continue;}else{plan_ways_map[candiates[i]]->parent = minidnode;plan_ways_map[candiates[i]]->G = tempg;plan_ways_map[candiates[i]]->F = Calculatef(candiates[i]);}}//如果结束点出现在openlist则搜索成功if(Isinlist(y, openlist)){plan_ways_map[y]->parent = minidnode;std::cout << "---------------------------------------------------" << std::endl;std::cout << "* find! *" << std::endl;int i = y;while(i != -1){plan_path.push_back(i);i = plan_ways_map[i]->parent;}std::reverse(plan_path.begin(), plan_path.end());isfindpath = true;return;}}}std::cout << "---------------------------------------------------" << std::endl;std::cout << "* not find! *" << std::endl;return;
}

其他函数

//计算起点到当前点的代价
double Calculateg(const int x, const int idg) const 
{}//估计当前点到终点的代价
double Calculateh(const int y, const int idh) const 
{}//计算总代价,预置A*接口,Dijkstra相当于简化版A*
double Calculatef(const int idf) const 
{}//从list中找出总代价的点
int Findleastf(const std::list<int> &listx) const 
{}//从当前索引idx找到可行的下一点集合
std::vector<int> Getnextnode(const int idx) const 
{}//判断x点是否在list中
bool Isinlist(const int x, const std::list<int> &listx) const 
{}

三、可优化空间

  • 1、选择排序更快的二叉树来作为开放列表,帮助我们更快地从开放列表中取出F值最小的点;
  • 2、对何种情况下可以走斜线路径加以判断;
  • 3、采用布兰森汉姆算法预先判断两点是否可以直接通行,可通行就直接返回两点的直线路径,不可直接通行再采用A星算法寻路,提高寻路效率;
  • 4、A星算法得出寻路路径后,可采用弗洛伊德算法对路径进行平滑处理,使人物走动更为自然
  • 5、设计两个或者更多寻路系统以便使用在不同场合,取决于路径的长度。这也正是专业人士的做法,用大的区域计算长的路径,然后在接近目标的时候切换到使用小格子/区域的精细寻路。
  • 6. 从起点和终点同时开始找,双向A*

四、参考文献

1.Introduction to the A* Algorithm

2.路径规划之 A* 算法 - 知乎

3.【寻路】A星算法浅析 - 知乎


http://chatgpt.dhexx.cn/article/Z3bw1utR.shtml

相关文章

激光SLAM之NDT算法(1)算法原理

/在激光SLAM之NDT算法&#xff08;2&#xff09;-建图中我会给出实测可用的建图代码,并予以解释代码结构,这里就先讲讲原理吧!!!/ 无人车激光SLAM系统简单可以分为建图和定位两部分&#xff0c;无人车的定位问题&#xff0c;实际上就是要找出无人车当前在地图的那个位置&#x…

A*算法的原理及应用

A*算法的原理 A* 算法是一种高效的启发式搜索算法&#xff0c;在二维的栅格地图上寻路效果好&#xff0c;它通过估算节点的代价评估函数值并作为节点的综合优先级&#xff0c;当选择下一个需要遍历的节点时&#xff0c;再选取综合优先级最高的节点&#xff0c;逐步地找到最优路…

Bresenham 画圆算法原理

文章目录 前言Bresenham 画圆算法原理两个近似构造判别式圆与网格点的关系关系由来关系含义p i p_i pi​ 递推画圆程序伪码圆与网格点的关系图示前言 首先简要介绍一下生成圆的方法: 直接利用圆的方程生成圆利用圆的对称性生成圆方法一由于会涉及到浮点运算等因素,不采取该方…

Js中读取、移除属性及隐藏组件方法研究

添加、移除组件属性方法: $(".class名").attr("属性名","属性值");//设置指定属性 $(".class名").attr("属性名");//读取指定属性值 or document.getElementById("id值").getAttribute("属性名…

js获取属性值,自定义属性,修改移除属性值

补充&#xff1a;由于不清楚一些属性是内置属性还是自定义属性 所以h5规定 自定义属性使用date-开头作为属性并赋值 案例1: <body><div date-index"1"></div> </body> <script>var div document.querySelector(div);console.log(div…

获取/移除属性值

1.获取属性值&#xff1a; element.属性 获取属性值 element.getAttribute&#xff08;‘属性’&#xff09;&#xff1b; 2.区别&#xff1a; element.属性 获取内置属性值&#xff08;元素本身自带的属性&#xff09; element.getAttribute&#xff08;‘属性’&#xff09;&…

JavaScript移除对象中不必要的属性

Thinking系列&#xff0c;旨在利用10分钟的时间传达一种可落地的编程思想。 业务开发中&#xff0c;我们经常会遇到&#xff1a;基于后端返回接口数据&#xff0c;前端保存到对象 Object 中&#xff0c;前端开发过程中为了一些场景的便利性&#xff0c;需要在该对象中增加相应的…

js移除属性

一、效果 代码 <style>div{width:100px;height: 100px;background-color: red;}.clsP{background-color: #00FF00;}</style><body><input type"button" value"移除属性" id"btn" /><div id"dv" score&q…

合天网安实验室CTF-解密100-Funny Crypto

合天网安实验室CTF-解密100-Funny Crypto 题目描述 tgbnjuy 8ujko9 5rfgy6 相关附件 题目链接 参考解题步骤 字母被围起来的字母图示颜色tgbnjuyh红8ujko9i绿5rfgy6t蓝 提交flag&#xff1a;hit

数字取证之Autopsy ——合天网安实验室学习笔记

实验链接 Autopsy Forensic Browser 是数字取证工具-The Sleuth Kit&#xff08;TSK&#xff09;的图形界面&#xff0c;用于对文件系统和卷进行取证。通过本实验学习文件系统取证的思想与方法&#xff0c;掌握Autopsy的使用。 链接&#xff1a;http://www.hetianlab.com/exp…

【合天网安】CONN.ASP暴库漏洞实验

0x01预备知识 1、概念&#xff1a; 相对路径和绝对路径 绝对路径&#xff1a;例如D&#xff1a;/test/test.mdb 相对路径&#xff1a;例如/test/test.mdb 2、%5C暴库 简单点说&#xff0c;就是在打开页面的时候把网页中的/换成%5C&#xff0c;然后提交就可以得到数据库地址…

【合天网安】FCKeditor 2.4.3文件上传漏洞

【合天网安实验室】FCKeditor 2.4.3文件上传漏洞 编辑器漏洞 常见的文本编辑器有FCKeditor、Ewebeditor、UEditor、KindEditor、XHeditor等&#xff0c;它们包含的功能类似&#xff0c;如图片上传、视频上传、远程下载等。使用这类编辑器减少了程序开发的时间&#xff0c;但也…

摩尔斯电码和栅栏密码 ——合天网安实验室学习笔记

实验链接 通过学习本实验理解摩尔斯电码和栅栏密码的编码解码过程&#xff1b;掌握编写摩尔斯电码的编码解码程序和编写多功能栅栏密码的编码解码程序。 链接&#xff1a;http://www.hetianlab.com/expc.do?ce64d3e661-ebbb-41fd-a220-a17d608f994e 实验简介 实验所属系列…

【合天网安】DoraBox之文件包含及任意文件读取漏洞

【合天网安实验室】DoraBox之文件包含及任意文件读取漏洞 目的&#xff1a; 过DoraBox靶场系列练习&#xff0c;学习任意文件包含、目录限制文件包含及任意文件读取漏洞的利用过程。 实验过程&#xff1a; 1.确保Apache、MySQL服务正常开启 2、查看.txt文本内容 3.使用includ…

合天网安实验室-sql注入实验一

根据指导书我们要先在实验机进入这个网址http://10.1.1.11:81 进入之后会看到三个实例。 实例一 根据指导书的提示来做这一题。后面两个实例也要看这个指导书。 先判断是否存在注入 方法一 在参数后面加上单引号,比如: http://xxx/abc.php?id1’ 如果页面返回错误&#xff…

合天网安《Weekly CTF》第四周

Check your source code 题目介绍 打开靶机&#xff0c;进步网站&#xff0c;是一个登陆框 首先&#xff0c;根据题名的提示&#xff0c;f12&#xff0c;发现存在source.txt 打开source.txt&#xff0c;出现源码 对源码进行分析 <?php $flag "XXXXXXXXXXXX"…

计算机取证之Xplico ——合天网安实验室学习笔记

实验链接 Xplico是一款开源的网络取证分析工具&#xff0c;其分析与呈现的能力非常强大。Xplico可以捕获Internet网络应用层流量&#xff0c;通过流量解析&#xff0c;解析出网络包中的各种应用数据&#xff0c;还原网络数据发送现场。通过本实验学习掌握Xplico使用方法&#…

合天网安实验室CTF-Exp200-Come on,Exploit me!

合天网安实验室CTF-Exp200-Come on,Exploit me! 题目描述 Audrey Tang. ⊙.⊙ 我只能说到这儿了 相关附件 exp200 题目链接 参考解题步骤 1、下载附件先用VSCode打开看看 换个行看看 通过and换行有68行 2、根据题目描述猜测   如果没有接触过perl语言看到这些文本应该…

CTF挑战赛-合天网安实验室

[TOCCTF挑战赛-合天网安实验室逆向解析] http://www.hetianlab.com/CTFrace.html 1.逆向100 修改后缀为.apk 安卓模拟器打开&#xff0c;发现要求输入Password 用Android逆向助手打开&#xff0c;dex转jar&#xff0c;发现明文password 输入&#xff0c;得到flag。 2.逆向200 …

内存取证之Volatility ——合天网安实验室学习笔记

实验链接 Volatility是一款顶级的开源内存取证分析工具&#xff0c;支持Windows&#xff0c;Linux&#xff0c;MaC&#xff0c;Android等系统的内存取证&#xff0c;它由Python编写成&#xff0c;通过本实验学习内存取证的思想与方法&#xff0c;掌握volatility的使用。 链接…