前言

A*搜寻算法俗称A星算法。这是一种在图形平面上,有多个节点的路径,求出最低通过成本的算法。常用于游戏中

通过二维数组构建的一个迷宫,“%”表示墙壁,A为起点,B为终点,“#”代表障碍物,“*”代表算法计算后的路径

本文实例代码结构:

% % % % % % %

% o o o o o %

% o o # o o %

% A o # o B %

% o o # o o %

% o o o o o %

% % % % % % %

=============================

经过A*算法计算后

=============================

% % % % % % %

% o o * o o %

% o * # * o %

% A o # o B %

% o o # o o %

% o o o o o %

% % % % % % % <

算法理论

算法的核心公式为:F=G+H

把地图上的节点看成一个网格。

G=从起点A,沿着产生的路径,移动到网格上指定节点的移动消耗,在这个例子里,我们令水平或者垂直移动的耗费为10,对角线方向耗费为14。我们取这些值是因为沿对角线

的距离是沿水平或垂直移动耗费的的根号2,或者约1.414倍。为了简化,我们用10和14近似。

既然我们在计算沿特定路径通往某个方格的G值,求值的方法就是取它父节点的G值,然后依照它相对父节点是对角线方向或者直角方向(非对角线),分别增加14和10。例子中这

个方法的需求会变得更多,因为我们从起点方格以外获取了不止一个方格。

H=从当前格移动到终点B的预估移动消耗。为什么叫”预估“呢,因为我们没有办法事先知道路径的长度,这里我们使用曼哈顿方法,它计算从当前格到目的格之间水平和垂直

的方格的数量总和,忽略对角线方向。然后把结果乘以10。

F的值是G和H的和,这是我们用来判断优先路径的标准,F值最小的格,我们认为是优先的路径节点。

实现步骤

算法使用java写的,先看一看节点类的内容

package a_star_search;

/**

* 节点类

* @author zx

*

*/

public class Node {

private int x; //x坐标

private int y; //y坐标

private String value; //表示节点的值

private double FValue = 0; //F值

private double GValue = 0; //G值

private double HValue = 0; //H值

private boolean Reachable; //是否可到达(是否为障碍物)

private Node PNode; //父节点

public Node(int x, int y, String value, boolean reachable) {

super();

this.x = x;

this.y = y;

this.value = value;

Reachable = reachable;

}

public Node() {

super();

}

public int getX() {

return x;

}

public void setX(int x) {

this.x = x;

}

public int getY() {

return y;

}

public void setY(int y) {

this.y = y;

}

public String getValue() {

return value;

}

public void setValue(String value) {

this.value = value;

}

public double getFValue() {

return FValue;

}

public void setFValue(double fValue) {

FValue = fValue;

}

public double getGValue() {

return GValue;

}

public void setGValue(double gValue) {

GValue = gValue;

}

public double getHValue() {

return HValue;

}

public void setHValue(double hValue) {

HValue = hValue;

}

public boolean isReachable() {

return Reachable;

}

public void setReachable(boolean reachable) {

Reachable = reachable;

}

public Node getPNode() {

return PNode;

}

public void setPNode(Node pNode) {

PNode = pNode;

}

}

还需要一个地图类,在map的构造方法中,我通过创建节点的二维数组来实现一个迷宫地图,其中包括起点和终点

package a_star_search;

public class Map {

private Node[][] map;

//节点数组

private Node startNode;

//起点

private Node endNode;

//终点

public Map() {

map = new Node[7][7];

for (int i = 0;i<7;i++){

for (int j = 0;j<7;j++){

map[i][j] = new Node(i,j,"o",true);

}

}

for (int d = 0;d<7;d++){

map[0][d].setValue("%");

map[0][d].setReachable(false);

map[d][0].setValue("%");

map[d][0].setReachable(false);

map[6][d].setValue("%");

map[6][d].setReachable(false);

map[d][6].setValue("%");

map[d][6].setReachable(false);

}

map[3][1].setValue("A");

startNode = map[3][1];

map[3][5].setValue("B");

endNode = map[3][5];

for (int k = 1;k<=3;k++){

map[k+1][3].setValue("#");

map[k+1][3].setReachable(false);

}

}

//展示地图

public void ShowMap(){

for (int i = 0;i<7;i++){

for (int j = 0;j<7;j++){

System.out.print(map[i][j].getValue()+" ");

}

System.out.println("");

}

}

public Node[][] getMap() {

return map;

}

public void setMap(Node[][] map) {

this.map = map;

}

public Node getStartNode() {

return startNode;

}

public void setStartNode(Node startNode) {

this.startNode = startNode;

}

public Node getEndNode() {

return endNode;

}

public void setEndNode(Node endNode) {

this.endNode = endNode;

}

}

下面是最重要的AStar类

操作过程

1从起点A开始,并且把它作为待处理点存入一个“开启列表”,这是一个待检查方格的列表。

2寻找起点周围所有可到达或者可通过的方格,跳过无法通过的方格。也把他们加入开启列表。为所有这些方格保存点A作为“父方格”。当我们想描述路径的时候,父方格的资

料是十分重要的。后面会解释它的具体用途。

3从开启列表中删除起点A,把它加入到一个“关闭列表”,列表中保存所有不需要再次检查的方格。

经过以上步骤,“开启列表”中包含了起点A周围除了障碍物的所有节点。他们的父节点都是A,通过前面讲的F=G+H的公式,计算每个节点的G,H,F值,并按照F的值大小,从小

到大进行排序。并对F值最小的那个节点做以下操作

4,把它从开启列表中删除,然后添加到关闭列表中。

5,检查所有相邻格子。跳过那些不可通过的(1.在”关闭列表“中,2.障碍物),把他们添加进开启列表,如果他们还不在里面的话。把选中的方格作为新的方格的父节点。

6,如果某个相邻格已经在开启列表里了,检查现在的这条路径是否更好。换句话说,检查如果我们用新的路径到达它的话,G值是否会更低一些。如果不是,那就什么都不

做。(这里,我的代码中并没有判断)

7,我们重复这个过程,直到目标格(终点“B”)被添加进“开启列表”,说明终点B已经在上一个添加进“关闭列表”的节点的周围,只需走一步,即可到达终点B。

8,我们将终点B添加到“关闭列表”

9,最后一步,我们要将从起点A到终点B的路径表示出来。父节点的作用就显示出来了,通过“关闭列表”中的终点节点的父节点,改变其value值,顺藤摸瓜即可以显示出路径。

看看代码

package a_star_search;

import java.util.ArrayList;

public class AStar {

/**

* 使用ArrayList数组作为“开启列表”和“关闭列表”

*/

ArrayList open = new ArrayList();

ArrayList close = new ArrayList();

/**

* 获取H值

* @param currentNode:当前节点

* @param endNode:终点

* @return

*/

public double getHValue(Node currentNode,Node endNode){

return (Math.abs(currentNode.getX() - endNode.getX()) + Math.abs(currentNode.getY() - endNode.getY()))*10;

}

/**

* 获取G值

* @param currentNode:当前节点

* @return

*/

public double getGValue(Node currentNode){

if(currentNode.getPNode()!=null){

if(currentNode.getX()==currentNode.getPNode().getX()||currentNode.getY()==currentNode.getPNode().getY()){

//判断当前节点与其父节点之间的位置关系(水平?对角线)

return currentNode.getGValue()+10;

}

return currentNode.getGValue()+14;

}

return currentNode.getGValue();

}

/**

* 获取F值 : G + H

* @param currentNode

* @return

*/

public double getFValue(Node currentNode){

return currentNode.getGValue()+currentNode.getHValue();

}

/**

* 将选中节点周围的节点添加进“开启列表”

* @param node

* @param map

*/

public void inOpen(Node node,Map map){

int x = node.getX();

int y = node.getY();

for (int i = 0;i<3;i++){

for (int j = 0;j<3;j++){

//判断条件为:节点为可到达的(即不是障碍物,不在关闭列表中),开启列表中不包含,不是选中节点

if(map.getMap()[x-1+i][y-1+j].isReachable()&&!open.contains(map.getMap()[x-1+i][y-1+j])&&!(x==(x-1+i)&&y==(y-1+j))){

map.getMap()[x-1+i][y-1+j].setPNode(map.getMap()[x][y]);

//将选中节点作为父节点

map.getMap()[x-1+i][y-1+j].setGValue(getGValue(map.getMap()[x-1+i][y-1+j]));

map.getMap()[x-1+i][y-1+j].setHValue(getHValue(map.getMap()[x-1+i][y-1+j],map.getEndNode()));

map.getMap()[x-1+i][y-1+j].setFValue(getFValue(map.getMap()[x-1+i][y-1+j]));

open.add(map.getMap()[x-1+i][y-1+j]);

}

}

}

}

/**

* 使用冒泡排序将开启列表中的节点按F值从小到大排序

* @param arr

*/

public void sort(ArrayList arr){

for (int i = 0;i

for (int j = i+1;j

if(arr.get(i).getFValue() > arr.get(j).getFValue()){

Node tmp = new Node();

tmp = arr.get(i);

arr.set(i, arr.get(j));

arr.set(j, tmp);

}

}

}

}

/**

* 将节点添加进”关闭列表“

* @param node

* @param open

*/

public void inClose(Node node,ArrayList open){

if(open.contains(node)){

node.setReachable(false);

//设置为不可达

open.remove(node);

close.add(node);

}

}

public void search(Map map){

//对起点即起点周围的节点进行操作

inOpen(map.getMap()[map.getStartNode().getX()][map.getStartNode().getY()],map);

close.add(map.getMap()[map.getStartNode().getX()][map.getStartNode().getY()]);

map.getMap()[map.getStartNode().getX()][map.getStartNode().getY()].setReachable(false);

map.getMap()[map.getStartNode().getX()][map.getStartNode().getY()].setPNode(map.getMap()[map.getStartNode().getX()][map.getStartNode().getY()]);

sort(open);

//重复步骤

do{

inOpen(open.get(0), map);

inClose(open.get(0), open);

sort(open);

}

while(!open.contains(map.getMap()[map.getEndNode().getX()][map.getEndNode().getY()]));

//知道开启列表中包含终点时,循环退出

inClose(map.getMap()[map.getEndNode().getX()][map.getEndNode().getY()], open);

showPath(close,map);

}

/**

* 将路径标记出来

* @param arr

* @param map

*/

public void showPath(ArrayList arr,Map map) {

if(arr.size()>0){

Node node = new Node();

// node = map.getMap()[map.getEndNode().getX()][map.getEndNode().getY()];

// while(!(node.getX() ==map.getStartNode().getX()&&node.getY() ==map.getStartNode().getY())){

// node.getPNode().setValue("*");

// node = node.getPNode();

// }

}

// map.getMap()[map.getStartNode().getX()][map.getStartNode().getY()].setValue("A");

}

}

最后写一个Main方法

package a_star_search;

public class MainTest {

public static void main(String[] args) {

Map map = new Map();

AStar aStar = new AStar();

map.ShowMap();

aStar.search(map);

System.out.println("=============================");

System.out.println("经过A*算法计算后");

System.out.println("=============================");

map.ShowMap();

}

}

修改地图再测试一下,看看效果

% % % % % % %

% o o o o o %

% o o # o o %

% A o # o B %

% o o # o o %

% o o o o o %

% % % % % % %

=============================

经过A*算法计算后

=============================

% % % % % % %

% o o o o o %

% o o # o o %

% A o # o B %

% o o # o o %

% o o o o o %

% % % % % % %

总结

保证找到最短路径(最优解的)条件,关键在于估价函数h(n)的选取:估价值h(n)<=n到目标节点的距离实际值,这种情况下,搜索的点数多,搜索范围大,效率低。但能得到

最优解。如果估价值>实际值,搜索的点数少,搜索范围小,效率高,但不能保证得到最优解。

最大的感触就是:做事最忌三天打渔,两天晒网。量可以不大,但必须有连续性,贵在坚持。

希望每一个程序员,都能开心的敲着代码,做自己喜欢做的事。

以上就是本文关于Java编程实现A*算法完整代码的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。

java做a_Java编程实现A*算法完整代码相关推荐

  1. Java常用的八种排序算法与代码实现

    在Java的时候,对于排序的应用需要熟练的掌握,这样才能够确保Java学习时候能够有扎实的基础能力.那Java有哪些排序算法呢?本文小千就来详细说说Java经典的8种排序算法. 经典的排序算法有八种, ...

  2. 用Java实现一个抽奖系统(附完整代码)

    作者:四原色 来源:https://blog.csdn.net/qq_44140450 需求分析 1)实现三个基本功能:登录.注册.抽奖. 2)登录:用户输入账号密码进行登录,输入账号后会匹配已注册的 ...

  3. Java实现猜数字游戏 简明 易懂 完整代码

    猜数字游戏 1 游戏规则 2 生成随机数 3 用户猜数 4 判定猜测正误 5 完整代码 6 运行结果 7 优化猜数字游戏 7.1 菜单模块 7.2 游戏模块 7.3 主控制模块 7.4 完整代码 1 ...

  4. Java实现ATM银行模拟系统(含完整代码)

    目录 引言 功能简介 登录和注册 1.注册 2.登录 具体功能实现 1.存款功能 2.取款功能 3.转账功能 4.查询功能 5.注销账号 6.修改密码 7.退出 完整代码 引言

  5. java迪杰斯特拉算法_迪杰斯特拉算法完整代码(Java)

    package com.rao.graph; import java.util.*; /** * @author Srao * @className Dijkstra * @date 2019/12/ ...

  6. java关于hashmap编程题_LeetCode算法题-Design HashMap(Java实现)

    这是悦乐书的第299次更新,第318篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第167题(顺位题号是706).在不使用任何内置哈希表库的情况下设计HashMap.具体 ...

  7. 一遍记住Java常用的八种排序算法与代码实现

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:KaelQ www.jianshu.com/p/5e1712 ...

  8. java小票_Java编程打印购物小票实现代码

    简单介绍运行环境: 语言:Java 工具:eclipse 系统:Windows7 (打印设备暂时没有,所以只能提供预览图) 最近,项目需要为商城做一个购物小票的打印功能,日常我们去超市买东西,结账的时 ...

  9. 天天酷跑电脑版代码C语言,Java实现天天酷跑小游戏完整代码(附源码).pdf

    Java实实现现天天天天酷酷跑跑小小游游戏戏完完整整代代码码(附附源源码码) 首首先先,,写写一一个个需需求求文文档档:: 一.项目名称: <天天酷跑> (RunDay ) 二.功能介绍: ...

最新文章

  1. Centos8 使用auditd配置系统审计
  2. 剑指 offer set 26 不用加减乘除做加法
  3. 几何视角看线性方程组解的情况
  4. python标准库书籍_Python标准库中文版 Python Standard Library 329页Python标准库合集
  5. C/C++/动态链接库DLL中函数的调用约定与名称修饰
  6. python中类的方法里面变量前加self与不加self的区别
  7. 【分享】一个集成tracert和ping的网络监测工具
  8. 10问10答:你真的了解线程池吗?
  9. 华为5G折叠屏手机,外媒猜长这样
  10. php firefox导出csv,如果文件名有空格,空格后面部分不会导出,后缀也没有
  11. Linux centosVMware mysql用户管理、常用sql语句、mysql数据库备份恢复
  12. 大规模WebGL应用引发浏览器崩溃的几种情况及解决办法
  13. PS网页设计教程XXI——在Photoshop中创建一个光质感网页设计
  14. SSM上传用户头像。解决HTTP 400,保存到本地以及数据库保存路径,在页面显示的问题
  15. SN/CF 5W-40含义
  16. 基于ECharts的职位地铁图的实现
  17. 三维荧光学习记录--在Origin中绘制三维荧光光谱图(补充)及荧光区域积分(FRI)
  18. java学习书籍推荐
  19. STC89C52串口向电脑发送数据
  20. 【KDD 2020】Local Community Detection in Multiple Networks

热门文章

  1. wxWidgets:wxDataViewTreeCtrl类用法
  2. boost::sort::block_indirect_sort相关的测试程序
  3. boost::python::iterator相关的测试程序
  4. boost::hana::eval用法的测试程序
  5. boost::intrusive::rbtree_algorithms用法的测试程序
  6. boost::gil::generate_gaussian_kernel用法的测试程序
  7. boost::describe模块宏BOOST_DESCRIBE_PP_PARSE的测试程序
  8. GDCM:gdcm::ByteBuffer的测试程序
  9. Boost:circular buffer的测试程序
  10. java数据结构有哪些_java有哪些数据结构?