一种单目标A*算法设计与实现

news/2024/9/24 14:03:40/文章来源:https://www.cnblogs.com/cloud-ken/p/18429018

一种单目标A*算法设计与实现

作者:吴屏珊

  • 最近在学习简单的单目标A*算法,其中在CSDN上阅读到的一篇博文给了我很大启发,于是在该博文的基础上,笔者记录了一点自己对于A*算法的体会和感悟。
  • 原文链接

目录

目录
  • 一种单目标A*算法设计与实现
    • 目录
    • 1. A*算法简单介绍
      • 1.1 A*算法的基本要素
      • 1.2 A*算法的中心思想
      • 1.3 A*算法所需数据结构
        • 1.3.1 定义点Node的结构
        • 1.3.2 记录点状态的几个表
    • 2. A*算法步骤演示
      • 2.1 第一轮操作
      • 2.2 第二轮操作
    • 3. A*算法实现代码
      • 3.1 定义Node类
      • 3.2 Solution方法
      • 3.3 main方法
      • 3.4 输出结果


1. A*算法简单介绍

1.1 A*算法的基本要素

Image
1、图的说明:有一个8*8的地图,其中绿色的点为起点,红色的点为终点,黑色的点为障碍点(即不可达点),当然边界也是不可达点。

2、将要实现的目标:从起点走到终点,其中要求所走距离最短并且要绕开所有不可达点。
3、移动方向:每个点只有上,下,左,右四个方向可以行进。

1.2 A*算法的中心思想

  • 我们首先思考一个问题作为引入:既然每一个点有四种移动方向,那如何判断该点下一步的移动方向呢,如何选出在该点下一步即将到达的所有点中选出最好的点呢?
    (1)这里我们需要用到一个公式:F=G+H;其中F称为代价,G为从起点到该点已走过的距离,H为从该点到终点将走的曼哈顿距离。
    (2)曼哈顿距离:在地图上我们忽略所有障碍点(不可达点),两点的横坐标之差的绝对值与纵坐标之差的绝对值之和即为两点之间的曼哈顿距离,数学公式表示如下:\({|x_1-x_2|+|y_1-y_2|}\) ;代码表示如下:Math.abs(x1-x2)+Math.abs(y1-y2)
    (3)选取移动方向的依据:F,每次移动前,计算下一步可到达点的 F 值,然后对所有可到达点(不限于下一步)的 F 值进行比较,优先选取移动代价最小即 F 值最小的点。

1.3 A*算法所需数据结构

1.3.1 定义点Node的结构

1、点的坐标(x,y)
2、计算点的代价时所需数值:F,G,H
3、父节点:Father;父节点记录的是该节点的上一个节点(即该节点是由哪个节点遍历到的)。
父节点的作用:A*算法从起点开始寻路,当找到终点的时候代表最短路径已经找到,这时我们可以利用终点结构的Father来回溯到起点(起点的Father为NULL),从而找出并且输出这条最短路径。

1.3.2 记录点状态的几个表

1、优先队列Open表:记录由该点下一步可以到达的所有点,并且每次将F值最小的点放在队首。
2、Close表:记录所有已经走过的点。
3、Exist表:记录所有遍历过的点(即在Open与Close中出现过的点)。
4、Close表与Exist表的区别:Close中存储的点是已走过的点,Exist表中存储的点是已遍历过,但不一定走过的点。

2. A*算法步骤演示

  • Open表不为空且未找到终点时一直进行循环

2.1 第一轮操作

  • 首先我们将起点放入Open表中

    alt textalt text
  • 在Open表中找到当前F值最小的结点A,并将该点移出Open表,加入到Close表中。
  • 遍历该点A四周所有可到达节点,如果这些节点不包含在Exist表中(即未出现过),则计算它们的F值,并且根据F值大小顺序加入到Open表中。

    alt textalt text
  • 记录这些点的父节点为该点A。

    alt text

2.2 第二轮操作

  • 在第一轮操作结束后的Open表中,将队首节点(即F值最小的节点)移出Open表,加入到Close表中。
  • 遍历该点B四周所有可到达节点,如果这些节点不包含在Exist表中(即未出现过),则计算它们的F值,并且根据F值大小顺序加入到Open表中。
  • (3,3)节点为障碍物,(3,1)节点已被Exist表包含,所以两个点都不加入到Open表中。

    alt textalt text
  • 记录新加入这些点的父节点为该点B。

    alt text

3. A*算法实现代码

3.1 定义Node类

  • init_Node(Father,end):传入父节点和终点,并计算两者间的曼哈顿距离,最终根据公式算出该点的F值。
  • compareTo(Node):用于比较出F值最小的点
class Node implements Comparable<Node> {public int x;  //x坐标public int y;  //y坐标public int F;  //F属性public int G;  //G属性public int H;  //H属性public Node Father;    //此结点的上一个结点//获取当前结点的坐标public Node(int x, int y) {this.x = x;this.y = y;}//通过结点的坐标可以得到F, G, H三个属性//需要传入这个节点的上一个节点和最终的结点public void init_node(Node father, Node end) {//father是父节点this.Father = father;if (this.Father != null) {this.G = father.G + 1;} else { //父节点为空代表它是第一个结点this.G = 0;}//计算通过现在的结点的位置和最终结点的位置计算H值this.H = Math.abs(this.x - end.x) + Math.abs(this.y - end.y);this.F = this.G + this.H;}// 用来进行和其他的Node类进行比较@Overridepublic int compareTo(Node o) {return Integer.compare(this.F, o.F);}
}

3.2 Solution方法

  • is_exist方法:判断是否在Exist表中出现过。
public boolean is_exist(Node node){for (Node exist_node : Exist) {if (node.x == exist_node.x && node.y == exist_node.y) {return true;}}return false;}
  • is_valid方法:判断是否合法(边界,不可达点,已存在于Exist表中都为不合法)
public boolean is_valid(int x, int y) {// 如果结点的位置是-1,则不合法if (map[x][y] == -1) return false;for (Node node : Exist) {//如果结点出现过,不合法
//            if (node.x == x && node.y == y) {
//                return false;
//            }if (is_exist(new Node(x, y))) {return false;}}//以上情况都没有则合法return true;}
  • extend_current_node方法:遍历该点的上下左右四个方向,并判断这些点是否合法。
public ArrayList<Node> extend_current_node(Node current_node) {int x = current_node.x;int y = current_node.y;ArrayList<Node> neighbour_node = new ArrayList<Node>();if (is_valid(x + 1, y)){Node node = new Node(x + 1, y);neighbour_node.add(node);}if (is_valid(x - 1, y)){Node node = new Node(x -1, y);neighbour_node.add(node);}if (is_valid(x, y + 1)){Node node = new Node(x, y + 1);neighbour_node.add(node);}if (is_valid(x, y - 1)){Node node = new Node(x, y - 1);neighbour_node.add(node);}return neighbour_node;}
  • astarSearch方法:A*算法具体实现方法。
public Node astarSearch(Node start, Node end) {//把第一个开始的结点加入到Open表中this.Open.add(start);//把出现过的结点加入到Exist表中this.Exist.add(start);//主循环while (Open.size() > 0) {//取优先队列顶部元素并且把这个元素从Open表中删除Node current_node = Open.poll();//将这个结点加入到Close表中Close.add(current_node);//对当前结点进行扩展,得到一个四周结点的数组ArrayList<Node> neighbour_node = extend_current_node(current_node);//对这个结点遍历,看是否有目标结点出现//没有出现目标结点再看是否出现过for (Node node : neighbour_node) {if (node.x == end.x && node.y == end.y) {//找到目标结点就返回node.init_node(current_node,end);return node;//返回的是终止结点}if (!is_exist(node)) {  //没出现过的结点加入到Open表中并且设置父节点node.init_node(current_node, end);Open.add(node);Exist.add(node);}}}//如果遍历完所有出现的结点都没有找到最终的结点,返回nullreturn null;}

3.3 main方法

  • 绘制8*8地图,并设置好起点和终点(原文直接在地图中进行起点终点的设置,修改起点和终点时相对麻烦,我在这里对原文进行了改进,在代码中设置起点终点,测试不同种情况时相对便捷)。
int[][] map = {{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},{-1,  0,  0,  0,  0,  0,  0,  0,  0, -1},{-1,  0,  0,  0,  0, -1,  0,  0,  0, -1},{-1,  0,  0,  0, -1,  0,  0,  0,  0, -1},{-1,  0,  0,  0, -1,  0,  0,  0,  0, -1},{-1,  0,  0,  0,  0, -1,  0,  0,  0, -1},{-1,  0,  0,  0, -1,  0,  0,  0,  0, -1},{-1,  0,  0,  0,  0, -1,  0,  0,  0, -1},{-1,  0,  0,  0,  0,  0,  0,  0,  0, -1},{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}};Node start = new Node(4, 2);map[start.x][start.y]=1;start.Father = null;Node end = new Node(4, 7);map[end.x][end.y]=2;
  • 调用Solution函数,拿到最短路径
Solution solution = new Solution();Node res_node = solution.astarSearch(start, end);//res—node最先接收的是该地图的终止while (res_node != null) {map[res_node.x][res_node.y] = res_node.G;res_node = res_node.Father;//迭代操作,从终止结点开始向后退,直到起点的父节点为null。循环终止}
  • 输出路径,我在这里对输出地图进行了一定程度上的渲染,红色代表边界和障碍不可达点,绿色代表起点和终点,蓝色代表路径,数字代表所走的步数(我在这里进行了改进,使输出地图更加直观)。
//渲染迷宫for (int i = 0; i < 10; i++){for (int j = 0; j < 10; j++){Node nownode =new Node(i,j);if(map[i][j]==-1)System.out.printf("\033[31m%3d\033[0m", map[i][j]);//redelse if (equal_node(nownode,start) || equal_node(nownode,end))System.out.printf("\033[32m%3d\033[0m", map[i][j]);//greenelse if(map[i][j]==0 && !equal_node(nownode,start))System.out.printf("%3d", map[i][j]);//blackelseSystem.out.printf("\033[34m%3d\033[0m", map[i][j]);//blue}System.out.println();}

3.4 输出结果


Image

源代码已保存到课题组github文件夹

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/802822.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI智能写作时代来临:如何高效提升你的文案创作能力

随着人工智能技术的飞速发展,AI智能写作已经不再是遥不可及的概念,而是逐渐成为内容创作者的得力助手。在这个信息过载的时代,如何利用AI智能写作工具高效提升文案创作能力,成为了许多创作者关注的焦点。以下将从几个方面探讨如何在AI智能写作时代,提升个人的文案创作能力…

南沙C++信奥老师解一本通题 1264:【例9.8】合唱队形

​【题目描述】N位同学站成一排,音乐老师要请其中的(N−K)位同学出列,使得剩下的K位同学排成合唱队形。 合唱队形是指这样的一种队形:设KK位同学从左到右依次编号为1,2,…,K1,2,…,K,他们的身高分别为T1,T2,…,TK,则他们的身高满足T1<T2<…<Ti,Ti>Ti+1>…&…

Accelerate 1.0.0

Accelerate 发展概况 在三年半以前、项目发起之初时,Accelerate 的目标还只是制作一个简单框架,通过一个低层的抽象来简化多 GPU 或 TPU 训练,以此替代原生的 PyTorch 训练流程:自此,Accelerate 开始不断扩展,逐渐成为一个有多方面能力的代码库。当前,像 Llama 这样的模型…

CloudFlare对接来此加密:实现域名自动验证 快速申请证书

使用ACME可以方便的申请证书,其中相对比较麻烦的是如何自动验证域名。 CloudFlare有两种接口凭证对接方式。 a)具有限制性的API Tokens。 b)具有所有权限的API Keys。 为了安全起见,来此加密只采用具有限制性的API Tokens,用户可以随时取消或修改,以保护CloudFlare的安全。…

后台管理前端设计器,个人商用1999!源码学习

WEB组态和大屏设计器,在IoT项目中十分常见,通常是这样:WEB组态 大屏设计器 但实际项目除了展示,通常还有后台管理。此前,这部分通常需要vue开发。有了UIOTOS,就能0基础,组态一样,搭建整个管理界面。 示例效果 这是一款前端零代码组态工具,无需学习js、html、css,能…

政企高校智能问答机器人系统-源码搭建部署

我们提供政企高校智能问答机器人系统,独立源码搭建部署 演示效果如图: 维♥:llike620十年开发经验程序员,离职全心创业中,历时三年开发出的产品《唯一客服系统》一款基于Golang+Vue开发的在线客服系统,软件著作权编号:2021SR1462600。一套可私有化部署的网站在线客服系统…

裸露土堆智能识别检测系统

裸露土堆智能识别检测系统基于yolo计算机视觉深度学习技术,裸露土堆智能识别检测系统实时识别城市周边施工建筑工的土堆裸露情况,若裸露土堆智能识别检测系统发现画面中的土堆有超过40%部分没被绿色防尘网覆盖,系统则判定为裸露土堆进行抓拍预警回传到后台大数据监控平台,减…

CodeMaid:一款基于.NET开发的Visual Studio代码简化和整理实用插件

前言 今天大姚给大家分享一款由.NET开源、免费、强大的Visual Studio代码简化、整理、格式化实用插件:CodeMaid。 工具介绍 CodeMaid是一款由.NET开源、免费、强大的Visual Studio实用插件,旨在帮助开发者简化、清理和格式化他们的C#、C++、VB.NET、F#、XAML、CSS、LESS、SCS…

煤矿皮带跑偏撕裂智能检测系统

煤矿皮带跑偏撕裂智能检测系统能够通过深度学习技术实时监测运输皮带的状况,当煤矿皮带跑偏撕裂智能检测系统监测到皮带出现撕裂跑偏时,立刻抓拍告警并中止皮带的运输,及时通知后台工作人员在第一时间到现场维修皮带。煤矿皮带跑偏撕裂智能检测系统可以提升后台监控人员对煤…

5号电池的相关科普

电池串联起来容量会增加吗? 当电池串联时,它们的电压会相加,但容量(即电池可以存储的电荷量)并不会改变。这意味着虽然电压提高了,但每个电池的存储能力并没有增强。因此,从容量角度看,串联电池并不会增加整体容量。对于问题中提到的“两组(2V100只串联300Ah)的电池组…

github pages使用cloudflare加速自定义域名概要

首先,整个操作涉及三个管理方githubpages cloudflare的DNS解析设置 自定义域名的解析设置其次,你需要知悉这些内容DNS及CNAME解析 github pages的基本部署 域名的基础管理 cloudflare的基本域名添加及解析管理概要步骤 github pages部分在github pages页面,先启用部署(Buil…

在 Xbox 主机上如何游戏录屏和游戏直播 All In One

在 Xbox 主机上如何游戏录屏和游戏直播 All In One在 Xbox 主机上如何游戏录屏和游戏直播 All In One errorsXbox 自带的游戏录屏分享只能录制 1分钟时长 💩solutions如何在 Xbox 上实时流式传输https://support.xbox.com/zh-SG/help/friends-social-activity/live-streaming…