A星算法(A* A Star algorithm)原理以及代码实例,超详细,超简单,大白话谁都能看懂

本文以这篇博主的文章为基础【精选】A*算法(超级详细讲解,附有举例的详细手写步骤)-CSDN博客

这篇文章的博主做了一个UI界面,但我感觉,这样对新手关注算法和代码本身反而不利,会被界面的代码所干扰。所以笔者在他的基础上舍去了界面的内容,只关注算法本身。

A星算法的作用就是:已知起点和终点坐标,将地图离散化为网格,可以使用A star算法寻路。

A star算法简单来说三个步骤:一是准备两个列表,开列表和闭列表,开列表将节点移进移出,闭列表只进不出。二是在每一步探索的时候,计算三个“花费”,起点走到当前点的实际花费 G,从当前点到目标点的预估花费 H, 总花费F = G + H。三是计算父节点,父节点的作用是推算花费以及到达终点后倒推路径。

具体来说,我们称现在所处的网格为 checking point k检查checking point k周围所有的下一步可到达点并『临时』将这些可到达点的父节点记为checking point k。可到达点是没有障碍物且不在闭列表中的网格(near point 1, near point 2, ......, near point i, ......, near point n),对于near point i,计算起点到near point i的实际花费:

起点到near point i的实际花费 = 起点到checking point k的实际花费 + checking point k到near point i的实际花费。

计算near point i到终点的预估花费:

near point i到终点的预估花费 = near point i到终点的曼哈顿距离。

near point i的总花费 = 实际花费 + 预估花费。这里只是“花费“的一种定义形式,也可以用其他的定义形式。

每个点都是我们建立的点类的类实例,在点类中储存这三个花费,以及储存父节点

如果near point i不在开列表中,将其加进去。注意我们前面『临时』标记的父节点,这里正式标记checking point k为父节点

如果near point i已经在开列表中,则说明,near point i在我们到达checking point k之前,处于另一个checking point j时,作为checking point j的可到达点被计算过了。这里我们比较一下near point i旧的总花费和新的总花费,如果新的总花费小,则更新花费,并把near point i的父节点更新为checking point k;如果旧的总花费小,则保持旧的花费,以及保持旧的父节点。

当checking point k的所有可到达点都被检查完后,将其移进闭列表

之后,从开列表中选一个总花费最小的点作为新的checking point,重复上述的检查可达点操作,直到找到终点,起始时,将起点加入开列表,如果在途中开列表空了,则不存在可达路径。

完整代码如下:

import numpy as np
import json
import matplotlib.pyplot as pltclass Map:def __init__(self):# 设置起点,终点所在的行列数,左上角为0,0start_row = 17start_col = 2end_row = 9end_col = 16with open('map.txt', 'r') as f:my_map = json.loads(f.read())my_map = np.array(my_map)self.map = np.where(my_map == 0, 1, np.where(my_map == 1, 0, my_map))self.map[start_row, start_col] = -100   # 起点self.map[end_row, end_col] = 100        # 终点# self.map = np.array([[1, 1, 1, 1, 0, 100],#                      [1, 0, 0, 1, 0, 1],#                      [1, -100, 0, 1, 0, 1],#                      [1, 1, 0, 1, 0, 1],#                      [1, 1, 1, 1, 1, 1]])def get_start_point(self):indices = np.where(self.map == -100)return indices[0][0], indices[1][0]def get_end_point(self):indices = np.where(self.map == 100)return indices[0][0], indices[1][0]def check_grid(self, point):return self.map[point.x, point.y]class Point:def __init__(self, x_, y_):self.x = x_self.y = y_self.father = Noneself.G = 0  # 起点到当前节点所花费的消耗self.H = 0  # 到终点的预估消耗self.F = 0def get_x_y(self):return self.x, self.ydef set_GHF(self, G, H, F):self.H = Hself.G = Gself.F = Fclass Astar:def __init__(self):self.openlist = []self.closelist = []self.map = Map()self.start_x, self.start_y = self.map.get_start_point()self.start_position = Noneself.end_x, self.end_y = self.map.get_end_point()self.find_path = Falseself.path = []def cal_GHF(self, checkpoint):if checkpoint.father is not None:G = checkpoint.father.G + 1   # 起点到父节点的花费加上父节点到本节点的花费else:G = 0H = abs(checkpoint.x - self.end_x) + abs(checkpoint.y - self.end_y)F = G + Hreturn G, H, Fdef add_near_point(self, check_point):x, y = check_point.get_x_y()tmp_list = [Point(x-1, y-1), Point(x-1, y), Point(x-1, y+1),Point(x, y-1), Point(x, y+1),Point(x+1, y-1), Point(x+1, y), Point(x+1, y+1)]near_list = []for pi in tmp_list:if self.map.map.shape[0] > pi.x >= 0 and self.map.map.shape[1] > pi.y >= 0:     # 在地图范围内if self.map.check_grid(pi) == 100:return [pi]elif self.map.check_grid(pi) == 1 and self.not_in_closelist(pi):near_list.append(pi)return near_listdef choose_min_F_point(self):minF = 1e10choosed_point = Nonefor pi in self.openlist:if pi.F < minF:minF = pi.Fchoosed_point = pireturn choosed_pointdef not_in_openlist(self, pi):not_in = Truefor pii in self.openlist:if pii.x == pi.x and pii.y == pi.y:not_in = Falsereturn not_indef not_in_closelist(self, pi):not_in = Truefor pii in self.closelist:if pii.x == pi.x and pii.y == pi.y:not_in = Falsereturn not_indef run(self):self.start_position = Point(self.start_x, self.start_y)G, H, F = self.cal_GHF(self.start_position)self.start_position.set_GHF(G, H, F)self.openlist.append(self.start_position)while True:checking_point = self.choose_min_F_point()if checking_point is None or self.find_path:print("End!")breakself.openlist.remove(checking_point)self.closelist.append(checking_point)near_list = self.add_near_point(checking_point)for pi in near_list:if self.map.check_grid(pi) == 100:self.find_path = True# print("find path:\n{}".format(checking_point.get_x_y()))self.path.append([checking_point.get_x_y()[0], checking_point.get_x_y()[1]])reverse_point_father = checking_point.fatherwhile reverse_point_father.father is not None:# print(reverse_point_father.get_x_y())self.path.append([reverse_point_father.get_x_y()[0], reverse_point_father.get_x_y()[1]])reverse_point_father = reverse_point_father.fatherbreakif self.not_in_openlist(pi):pi.father = checking_pointG, H, F = self.cal_GHF(pi)pi.set_GHF(G, H, F)self.openlist.append(pi)else:G_old = pi.G + 1G_new = checking_point.G + 1if G_new < G_old:pi.father = checking_pointG, H, F = self.cal_GHF(pi)pi.set_GHF(G, H, F)# 打印路性print("path: ")print(self.path)self.path = self.path[::-1]with open('my_path.txt', 'w') as file:for item in self.path:file.write(str(item) + '\n')def check(self):for pi in self.path:self.map.map[pi[0], pi[1]] = 2fig = plt.figure("A Star Algorithm")cmap = plt.cm.colors.ListedColormap(['yellow', 'black', 'white', 'blue', 'green'])# 创建一个离散的归一化器,根据不同数值映射到不同颜色bounds = [-101, -99, 0, 1, 2, 99, 101]norm = plt.cm.colors.BoundaryNorm(bounds, cmap.N)# 显示二维数组plt.imshow(self.map.map, cmap=cmap, norm=norm)# 添加颜色条,以便查看数值与颜色的对应关系cb = plt.colorbar()# 显示图plt.show()if __name__ == "__main__":astar = Astar()astar.run()astar.check()

使用我的代码前,可以先运行文章开头提到的那个博主的代码,生成一个地图保存,我的代码加载他的地图(也可以使用我注释掉的那个地图),我的地图中,1表示可行网格,0表示障碍物网格。如果我们足够幸运的话,我们两篇文章的结果应该是一致的。

 

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

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

相关文章

C++多态(超级详细版)

目录 一、什么是多态 二、多态的定义及实现 1.多态构成条件 2.虚函数的重写和协变 虚函数重写的两个例外&#xff1a; 2.1协变 2.2析构函数的重写 &#xff08;析构函数名统一处理成destructor&#xff09; 3.重载、覆盖(重写)、隐藏(重定义)的对比 4.final 和 overr…

大模型在数据分析场景下的能力评测

“你们能对接国产大模型吗&#xff1f;” “开源的 LLaMA 能用吗&#xff0c;中文支持怎么样&#xff1f;” “私有化部署和在线服务哪个更合适&#xff1f;” 自 7 月 14 日发布 AI 数智助理 Kyligence Copilot 后&#xff0c;我们收到了很多类似上面的咨询&#xff0c;尤其…

编程实例:洗车店会员管理系统软件一卡多项目管理编程

编程实例&#xff1a;洗车店会员管理系统软件一卡多项目管理编程 编程系统化课程总目录及明细&#xff0c;点击进入了解详情。 https://blog.csdn.net/qq_29129627/article/details/134073098?spm1001.2014.3001.5502 1、会员可以直接用手机号&#xff0c;并可以绑定车牌号 2…

软考系统架构之案例篇(软件工程相关概念)

案例篇-软件工程相关概念 1. 流程图和数据流图之间的区别与联系2. 状态图和活动图的含义及其区别3. 活动图和流程图的区别4. 数据流图中所包含的基本元素及其作用5. 数据流图的平衡原则:6. 用例之间的关系7. 类之间的关系以及基本含义8. 对象模型、动态模型和功能模型的含义以及…

虚拟化 vs. 裸金属:K8s 部署环境架构与特性对比

伴随着 IT 云化转型的逐步推进&#xff0c;越来越多的用户加入应用容器化改造的行列&#xff0c;并使用 Kubernetes&#xff08;K8s&#xff09;进行容器部署管理。然而&#xff0c;令不少用户感到困惑的是&#xff0c;由于大部分应用此前都部署在虚拟化或超融合环境&#xff0…

JVM相关面试题(每日一练)

1. 什么是垃圾回收机制&#xff1f; 垃圾收集 Garbage Collection 通常被称为“GC”&#xff0c;它诞生于1960年 MIT 的 Lisp 语言&#xff0c;经过半个多世纪&#xff0c;目前已经十分成熟了。 jvm 中&#xff0c;程序计数器、虚拟机栈、本地方法栈都是随线程而生随线程而灭&a…

在本地模拟C/S,Socket套接字的使用

public class SocketTCP01Server {public static void main(String[] args) throws IOException {/**1.在本机的 9999 端口监听 &#xff0c;等待连接细节&#xff1a; 要求在本机没有其他服务在监听999细节&#xff1a;这个ServerSocket 可以通过accept()返回多个Socket[多个客…

使用Jenkins触发gitlab的webhook

满足条件&#xff1a; 首先手动构建可以完成构建 例如&#xff1a; 打开项目点击配置 在“Build Triggers”栏勾选&#xff0c;Build when a change is pushed to GitLab. GitLab webhook &#xff1b;如下 复制URL链接&#xff0c;我的链接是&#xff1a;http://192.168.44…

设计模式之门面模式

前言 什么是门面模式 门面模式是一种结构型设计模式&#xff0c;它提供了一个统一的接口&#xff0c;用来访问子系统中的一群接口。它定义了一个高层接口&#xff0c;让子系统更容易使用。这种模式常用于将一个复杂的子系统封装成一个简单的接口&#xff0c;使得客户端可以方…

Java 枚举类型与泛型-第13章

Java 枚举类型与泛型-第13章 1.枚举类型 枚举类型是一种特殊的数据类型&#xff0c;用于表示一组有限的命名常量。枚举类型可以帮助您更清晰地定义和管理相关常量&#xff0c;并提供类型安全性。 1.1使用枚举类型设置常量 枚举类型是一种非常方便的方式来设置常量。我们可以…

基于51单片机的温度测量报警系统的设计与制作

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、实习目的二、实习任务2.1 设计温度测量报警系统硬件电路2.2 温度测量报警系统软件编程、仿真与调试&#xff1b;2.3 完成温度测量报警系统的实物制作与调试…

从一线到联合,克唑替尼在ALK阳性NSCLC治疗新旅程【医游记】

&#xff08;图片来源于网络&#xff09; 一、克唑替尼简介 克唑替尼(Crizotinib),商品名赛可瑞,是一款口服服用的小分子酪氨酸激酶抑制剂。克唑替尼最早于2011年被美国FDA批准用于ALK阳性晚期NSCLC的治疗。其主要靶点为间变淋巴瘤激酶(ALK)和ROS1(ROS proto-oncogene 1)融合…

3.1、Linux的vim编辑器

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 前言&#xff1a; 插入模式 底行模式 命令模式 前言&#xff1a; 没有进行配置的vim编辑器在写代码时和记事本没什么两样&#xff0c;所以最开始我们可以先下载一个插件&#xff0c;在Linux下两行指令的问题&…

视频格式高效转换:MP4视频批量转MKV格式的方法

随着数字媒体技术的不断发展&#xff0c;视频格式转换已经成为了我们日常工作中不可或缺的一部分。不同的视频格式适用于不同的场景和设备&#xff0c;因此将视频从一种格式转换为另一种格式往往是我们必须完成的任务。在本文中&#xff0c;我们将重点介绍如何运用云炫AI智剪高…

Apollo安装全攻略

安装方式 概述快速安装安装基础软件安装 Ubuntu Linux安装 Docker Engine 安装 Apollo 环境管理工具获取 GPU 支持&#xff08;可选&#xff09;创建和进入 Apollo 环境容器 源码安装安装 Linux 系统&#xff08;可选&#xff09;安装 NVIDIA GPU 驱动安装 docker下载并编译 Ap…

【Linux】安装配置解决CentosMobaXterm的使用及Linux常用命令命令模式

目录 一、介绍 1. 背景 2. 讲述&功能 二、Centos安装配置&MobaXterm 1. 创建 2. 安装 3. 配置 4. MobaXterm使用 三、Linux常用命令&模式 1. 常用命令 2. 三种模式 3. 命令使用&换源 4. 拍照备份 一、介绍 1. 背景 CentOS的背景可以追溯到200…

STM32F4X SDIO(二) SDIO协议

上一节简单介绍了SD卡的分类&#xff0c;本节将会介绍SD卡的通信协议&#xff0c;也就是SDIO协议。 STM32F4X SDIO&#xff08;二&#xff09;SDIO协议 SD 卡管脚和寄存器SD卡管脚分布SD卡通信协议SD卡寄存器SD卡内部结构 SDIO总线SDIO总线拓扑SDIO总线协议SDIO协议的基本结构…

java将list转为逗号隔开字符串,将逗号连接的字符串转成字符数组,​将逗号分隔的字符串转换为List​(Java逗号分隔-字符串与数组相互转换)

一、通过testList.stream().collect(Collectors.joining(",")) &#xff0c;通过流转换&#xff0c;将list转为逗号隔开字符串 List<String> testList new ArrayList<>(); testList.add("test1"); testList.add("test2"); testList…

ArcGIS笔记12_ArcGIS搜索工具没法用?ArcGIS运行很慢很卡?

本文目录 前言Step 1 ArcGIS搜索工具没法用Step 2 ArcGIS运行很慢很卡 前言 这是笔者最近遇到的两个小问题&#xff0c;新换了台式机&#xff0c;安装上ArcGIS后发现搜索工具没法用&#xff0c;而且感觉还不如原来笔记本运行的流畅&#xff0c;加载图层很慢&#xff0c;编辑要…

web - 前段三剑客

目录 前言 一. HTML 常用标签演示 图片标签 ​编辑 表格标签(重点) ​编辑 表单标签 (重点) 布局标签 其余标签 二. CSS 2.1 . css的三种引入方式 2.2 . 三大选择器 2.3 . css样式 - 浮动 2.4 . css样式 - 定位 1.static 2.absolute(绝对位置) 3.relavite(相…