A*算法启发式搜索

最短路径算法:

  A*算法擅长解决静态路径中最短距离问题,而又不同于Dijkstra算法和Floyd算法,该算法综合了BFS和Dijkstra算法优点:在进行启发式搜索提高算法效率的同时,可以保证找到一条最优路径(基于评估函数,例如:曼哈顿距离、欧式距离),Floyd算法更多地使用场景在于机器人路径规划、游戏规划、卫星路径探寻等领域。

A*算法与最短路径计算:

对于地理环境中的一个固定地面位置,它至少可以被标记为两种状态跟:可使用区、不可使用区(障碍区),同时可以把该固定位置视为九宫格里面的中心点。

可以确定该中心点的移动方向包含8个:上下左右,左上、右上、左下、右下,因此A*算法的寻路流程可以通过三个步骤完成。

1.从中心点开始,把它放入一个待计算的开放列表,开放列表可以理解成一个准备进行路径分析的队列。

2.寻找中心点周围可达到的方格集,这些方格的状态需要是可以使用的,将这些方格的来源都标记为中心点。

3.在开放列表中移除刚刚分析的中心点,将该中心点放入关闭列表中,关闭列表表示后续不再对该表进行可达路径分析。

通过3步已经完成了开放列表的获取,但是如何从开放列表中选择下一步的移动方格是A*算法思想中最核心的内容。A*算法利用公式f(n)=g(n)+h(n)筛选下一步移动方格,其中,g(n)代表从起初开始的方格移动当当前方格的移动距离;h(n)表示从即将移动到的方格到终点方格的距离,两者相加得到f(n)即为当前预估的可能路径,这种可能路径中最小的值对应的方格即为当前可以从开放列表中选择的下一步移动方格,选择该方格之后再依次重复上述步骤,知道邻近的方格中存在终点方格(或终点方格进入了开放列表)‘

上述步骤中g(n)和h(n)是获取A*计算计算的关键值

1.g(n)的计算

g(n)定义的是起点方格到当前方格的距离,从方格不同位置移动多产生的距离,在实际应用中,每个方向的距离都有可能不同,g(n)则是从起点方格开始通过不断的方位移动累计的距离和。

2.h(n)的计算

h(n)是对当前方格到目的地方格距离的估算,估算方法:

常见的距离计算公式有这么几种:

1、曼哈顿距离:这个名字听起来好高端,说白了,就是上面我们讲的横向格子数+纵向格子数;

2、欧式距离:这个名字听起来也很高端,说白了,就是两点间的直线距离sqrt((x1-x2)2 + (y1-y2)2)

算法源码:

Main.java:

package com.simplemain.astar;public class Main
{// 地图元素static final char START   = 'S';  // 起点static final char END     = 'E';  // 终点static final char SPACE   = '.';  // 空地static final char WALL    = 'W';  // 墙static final char VISITED = '-';  // 被访问过static final char ON_PATH = '@';  // 在结果路径上// 地图字符串static final String[] S_MAP = {". . . . . . . . . . . . . . . . . . . .", ". . . W W W W . . . . . . . . . . . . .",". . . . . . W . . . . . . . . . . . . .", ". . . . . . W . . . . . . . . . . . . .", ". . S . . . W . . . . . . . . . . . . .", ". . . . . . W . . . . . . . . . . . . .", ". . . . . . W . . . . . . . . . . . . .", ". . . . . . W . . . . . . . . . . . . .", ". . . W W W W . . . . . . . . . . . . .", ". . . . . . . . . . . . . . . . . E . ."};// 地图static char[][] MAP    = new char[S_MAP[0].replace(" ", "").length()][S_MAP.length];// 地图最大尺寸static Point MAX_PNT   = new Point(MAP.length, MAP[0].length);// 起点static Point START_PNT = null;// 终点static Point END_PNT   = null;public static void main(String[] args){genMap();printMap();search();printMap();}/*** 用地图字符串产生地图数据*/static void genMap(){int idx = 0;for (String s : S_MAP){char[] cs = s.replace(" ", "").toCharArray();for (int i = 0; i < cs.length; i++){MAP[i][idx] = cs[i];switch (cs[i]){case START:START_PNT = new Point(i, idx);break;case END:END_PNT = new Point(i, idx);break;}}idx++;}}/*** 打印地图*/static void printMap(){for (int j = 0; j < MAX_PNT.y; j++){for (int i = 0; i < MAX_PNT.x; i++){System.out.printf("%c ", MAP[i][j]);}System.out.printf("\n");}System.out.printf("\n");}/*** 搜索算法*/static void search(){final MinHeap heap = new MinHeap(); // 用最小堆来记录扩展的点final int[][] directs = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}}; // 可以扩展的四个方向heap.add(new Data(START_PNT, 0, 0, null)); // 把起始点放入堆Data lastData = null; // 找到的最后一个点的数据,用来反推路径for (boolean finish = false; !finish && !heap.isEmpty(); ){final Data data = heap.getAndRemoveMin(); // 取出f值最小的点final Point point = data.point;if (MAP[point.x][point.y] == SPACE) // 将取出的点标识为已访问点{MAP[point.x][point.y] = VISITED;}for (int[] d : directs) // 遍历四个方向的点{final Point newPnt = new Point(point.x + d[0], point.y + d[1]);if (newPnt.x >= 0 && newPnt.x < MAX_PNT.x && newPnt.y >= 0 && newPnt.y < MAX_PNT.y){char e = MAP[newPnt.x][newPnt.y];if (e == END) // 如果是终点,则跳出循环,不用再找{lastData = data;finish = true;break;}if (e != SPACE) // 如果不是空地,就不需要再扩展{continue;}final Data inQueueData = heap.find(newPnt);if (inQueueData != null) // 如果在堆里,则更新g值{if (inQueueData.g > data.g + 1){inQueueData.g = data.g + 1;inQueueData.parent = data;}}else // 如果不在堆里,则放入堆中{double h = h(newPnt);Data newData = new Data(newPnt, data.g + 1, h, data);heap.add(newData);}}}}// 反向找出路径for (Data pathData = lastData; pathData != null; ) {Point pnt = pathData.point;if (MAP[pnt.x][pnt.y] == VISITED){MAP[pnt.x][pnt.y] = ON_PATH;}pathData = pathData.parent;}}/*** h函数*/static double h(Point pnt){
//		return hBFS(pnt);return hEuclidianDistance(pnt);
//		return hPowEuclidianDistance(pnt);
//		return hManhattanDistance(pnt);}/*** 曼哈顿距离,小于等于实际值*/static double hManhattanDistance(Point pnt){return Math.abs(pnt.x - END_PNT.x) + Math.abs(pnt.y - END_PNT.y);}/*** 欧式距离,小于等于实际值*/static double hEuclidianDistance(Point pnt){return Math.sqrt(Math.pow(pnt.x - END_PNT.x, 2) + Math.pow(pnt.y - END_PNT.y, 2));}/*** 欧式距离平方,大于等于实际值*/static double hPowEuclidianDistance(Point pnt){return Math.pow(pnt.x - END_PNT.x, 2) + Math.pow(pnt.y - END_PNT.y, 2);}/*** BFS的h值,恒为0*/static double hBFS(Point pnt){return 0;}}

MinHeap.java:

package com.simplemain.astar;import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;public class MinHeap
{private final ArrayList<Data> queue = new ArrayList<>();private int endPnt = 0;private final Map<String, Data> index = new HashMap<>();public Data getAndRemoveMin(){if (isEmpty()){return null;}Data head = queue.get(0);Data last = queue.get(endPnt - 1);queue.set(0, last);endPnt--;index.remove(getKey(head.point));topDown();return head;}public Data find(Point pnt){return index.get(getKey(pnt));}public void add(Data data){if (queue.size() > endPnt){queue.set(endPnt, data);}else{queue.add(data);}endPnt++;index.put(getKey(data.point), data);bottomUp();}public boolean isEmpty(){return endPnt <= 0;}private String getKey(Point pnt){return String.format("%d-%d", pnt.x, pnt.y);}private void topDown(){for (int cur = 0; cur < endPnt; ){int left  = 2 * cur + 1;int right = 2 * cur + 2;Data dc = queue.get(cur);Data dl = left < endPnt ? queue.get(left) : null;Data dr = right < endPnt ? queue.get(right) : null;int next = -1;Data dn = dc;if (dl != null && dl.f() < dn.f()){next = left;dn = dl;}if (dr != null && dr.f() < dn.f()){next = right;dn = dr;}if (next >= 0 && next < endPnt){queue.set(next, dc);queue.set(cur, dn);cur = next;}else{break;}}}private void bottomUp(){for (int cur = endPnt - 1; cur >= 0; ){int parent = (cur - 1) / 2;if (parent < 0){break;}Data dc = queue.get(cur);Data dp = queue.get(parent);if (dc.f() < dp.f()){queue.set(parent, dc);queue.set(cur, dp);cur = parent;}else{break;}}}
}

Point.java:

package com.simplemain.astar;public class Point
{int x, y;Point(int x, int y){this.x = x;this.y = y;}public boolean equals(Object o){return o != null && o instanceof Point && ((Point)o).x == x && ((Point)o).y == y;}
}

Data.java:

package com.simplemain.astar;public class Data
{Point point;double g;double h;Data parent;public Data(Point p, double g, double h, Data parent){this.point = p;this.g = g;this.h = h;this.parent = parent;}double f(){return g + h;}
}

gitHub代码:https://github.com/simplemain/astar

代码出自:https://blog.csdn.net/qq_41325698/article/details/81874529

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

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

相关文章

基于维特比算法的概率路径

简介&#xff1a; 维特比算法(Vieterbi algorithm)是一种动态规划算法&#xff0c;探索出很多预测天气的方法&#xff0c;这种基于经验的预测方式&#xff0c;是一种基于历史数据的概率模型。 思想 维特比算法的思想是假设某一个数据的当前状态是依赖于它的前一个状态&#…

Python的Pexpect库

Pexpect 是一个用来启动子程序并对其进行自动控制的纯 Python 模块。 Pexpect 可以用来和像 ssh、ftp、passwd、telnet 等命令行程序进行自动交互。本文主要是针对ssh远程登录&#xff0c;然后执行简单的新建文件夹与拷贝任务Pexpect 的安装&#xff1a;下载&#xff1a;https:…

k-shingles和MinHash优秀文章保存

minhash原理解释&#xff1a;https://www.cnblogs.com/sddai/p/6110704.html k-shingles和minhash使用原理&#xff1a;https://blog.csdn.net/aspirinvagrant/article/details/41281101 代码java实现&#xff1a;https://blog.csdn.net/remoa_dengqinyi/article/details/728…

Python 数据库连接

#!/usr/bin/env python #-*-coding:utf-8-*- #异常处理&#xff0c;with的使用&#xff0c; class Mycontex(object):def __init__(self,name):self.namenamedef __enter__(self):print("__enter__")return selfdef do_self(self):print(do_self)def __exit__(self,e…

中文分词测试语句

研究生命科学研究生命令本科生我从马上下来我马上下来北京大学生喝进口红酒在北京大学生活区喝进口红酒从小学电脑从小学毕业美军中将竟公然说新建地铁中将禁止商业摊点这块地面积还真不小地面积了厚厚的雪让我们以爱心和平等来对待动物阿美首脑会议将讨论巴以和平等问题锌合金…

socket网络编程udp

#!/usr/bin/env python #-*-coding:utf-8-*- #udp socketserver客户端 import socketHOST127.0.0.1 PORT3214 ssocket.socket(socket.AF_INET,socket.SOCK_DGRAM)data你好&#xff01; s.sendto(data.encode(utf-8),(HOST,PORT))while data!bye:datbwhile len(dat)0:dat,addrs.…

几种分类器小结

朴素贝叶斯分类器是假设数据样本特征完全独立&#xff0c;以贝叶斯定理为基础的简单概率分类器。AdaBoost算法的自适应在于前一个分类器产生的错误分类样本会被用来训练下一个分类器&#xff0c;从而提升分类准确率&#xff0c;但是AdaBoost算法对于噪声样本和异常样本比较敏感…

socket网络编程tcp

#!/usr/bin/env python #-*-coding:utf-8-*- #tcp 客户端import socketHOST127.0.0.1 POST3214ssocket.socket() try:s.connect((HOST,POST))data你好&#xff01;while data:s.sendall(data.encode(utf-8))datas.recv(1024)print(Receive from Server:\n,data.decode(utf-8))d…

聚类算法篇章总结

主要的距离计算方法包括&#xff1a; 最短距离法(通过样本数值之间的距离计算&#xff0c;然后将距离值最小的样本进行合并的过程)最长距离法中间距离法重心法(重心聚类法&#xff1a;将两个聚类中心点的距离定义为两个类的重心距离&#xff0c;而类的重心为属于该类的样本的平…

socket网络编程多线程

#!/usr/bin/env python #-*-coding:utf-8-*- #多进程 import threading import time def thfun():s0for i in range(30):sitime.sleep(0.1)print(s)class MyThread(threading.Thread):def run(self):s0for i in range(30):sitime.sleep(0.1)print(s)if __name____main__:#ths[t…

学习之道

对待人生的任何事情都要&#xff1a;抓大放小&#xff0c;要事为先 对于一个以前从来没有接触过java的人&#xff0c;java无疑是庞大的&#xff0c;似乎每个领域都可以拓展开来都是一片开阔地&#xff0c;每一个领域要想深入接触到每一个细节所耗费的精力都是巨大的。这个时候大…

socket网络编程ftp

#!/usr/bin/env python #-*-coding:utf-8-*- #ftp客户端 import os import socket import threading import socketserver#下载文件 def get_file(host,port,filepath):ssocket.socket()s.connect((host,port))filepathos.path.join(.,bakc,filepath)fopen(filepath,wb)dataTr…

python类似于java的重写toString方法

python类中的特殊方法&#xff1a; __str__(self)用来重写 people类&#xff1a; class People:所有员工的基类#构造函数def __init__(self, user_id, user_name):self.user_id user_idself.user_name user_name#析构函数def __del__(self):class_name self.__class__.__n…

socket网络编程实现远程备份

#!/usr/bin/env python #-*-coding:utf-8-*- #GUI设计与构建 客户端建立from tkinter import * from tkinter.ttk import * import socket import struct#启动服务 def start(host,port):pass#我的控件 class MyFrame(Frame):def __init__(self,root):super().__init__(root)se…

python正则表达式使用

模板代码&#xff1a; import re #python 自1.5版本增加了re模块&#xff0c;它提供了Perl风格的正则表达式模式 print(re.match(www, www.baidu.com).span()) #在起初位置匹配 line "Cats are smarter than dogs" matchObj re.match( r(.*) are (.*?) .*, line,…

Q-学习,马克尔决策过程:强化学习

马尔可夫决策过程 马尔可夫决策过程是基于马尔可夫过程理论的随机动态系统的最优决策过程。马尔可夫决策过程是序贯决策的主要研究领域。它是马尔可夫过程与确定性的动态规划相结合的产物&#xff0c;故又称马尔可夫型随机动态规划&#xff0c;属于运筹学中数学规划的一个分支…

python对象使用

模板代码&#xff1a; class People:所有员工的基类#构造函数def __init__(self, user_id, user_name):self.user_id user_idself.user_name user_name#析构函数def __del__(self):class_name self.__class__.__name__print(class_name, 销毁)def get_info(self):print(&qu…

机器学习——决策树算法

机器学习——决策树算法原理及案例 标签&#xff1a; 机器学习决策树信息增益基尼指数模型评估 2016-05-04 15:31 43984人阅读 评论(1) 收藏 举报 分类&#xff1a; 机器学习&#xff08;10&#xff09; 版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不…

python运算符重载

重载符模板代码&#xff1a; class Vector:def __init__(self, a, b):self.a aself.b bdef __str__(self):return Vector (%d, %d) % (self.a, self.b)def __add__(self, other):return Vector(self.a other.a, self.b other.b) v1 Vector(2, 10) v2 Vector(5, -2) prin…