A*算法 JAVA实现
2016-07-13 14:46
453 查看
A*算法的java实现
本文内容参考于 —— [ 理解A*寻路算法具体过程 ]A*算法是一种启发式最小代价寻路算法,本文是在参考博文的基础上了解A*算法思想之后,使用java实现的,做个记录。
整个过程抽象:
把起始格添加到 "开启列表" do { 寻找开启列表中F值最低的格子, 我们称它为当前格. 把它切换到关闭列表. 对当前格相邻的8格中的每一个 if (它不可通过 || 已经在 "关闭列表" 中) { 什么也不做. } if (它不在开启列表中) { 把它添加进 "开启列表", 把当前格作为这一格的父节点, 计算这一格的 FGH } if (它已经在开启列表中) { if (用G值为参考检查新的路径是否更好, 更低的G值意味着更好的路径) { 把这一格的父节点改成当前格, 并且重新计算这一格的 GF 值. } } 目标格已经在 "开启列表", 这时候路径被找到跳出循环; } while(开启列表不为空) 如果开启列表已经空了,目标格没找到 说明路径不存在. 最后从目标格开始, 沿着每一格的父节点移动直到回到起始格, 这就是路径.
注:这个实现支持斜着走, 如果要实现不支持走沿对角的斜线,可以在此实现的基础上稍作修改即可实现。
JAVA实现的代码如下:
import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Scanner; import java.util.Stack; public class AStarAlgorithm { private static final int[][] DIREC = {{-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}}; public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("please enter (rows cols x1 y1 x2 y2): "); final int rows = scanner.nextInt(); final int cols = scanner.nextInt(); int x1 = scanner.nextInt(); int y1 = scanner.nextInt(); int x2 = scanner.nextInt(); int y2 = scanner.nextInt(); scanner.close(); // generate a two-dimension array filled with 0 int map[][] = new int[rows][cols]; for (int i = 0; i < rows; i++) { int tmp[] = new int[cols]; Arrays.fill(tmp, 0); map[i] = tmp; } int midr = rows / 2; int midc = cols / 2; /*map[midr - 1][midc] = 1; map[midr][midc] = 1; map[midr + 1][midc] = 1;*/ for (int i = 1; i < rows - 1; i++) { map[i][midc] = 1; } map[2][6] = 1; map[3][6] = 1; map[4][6] = 1; map[5][6] = 1; findPath(map, x1, y1, x2, y2); } private static void findPath(int[][] map, int x1, int y1, int x2, int y2) { List<Position> openList = new ArrayList<AStarAlgorithm.Position>(); List<Position> closeList = new ArrayList<AStarAlgorithm.Position>(); boolean findFlag = false; Position termPos = null; // 起始点 Position startPos = new Position(x1, y1, calcH(x1, y1, x2, y2)); openList.add(startPos); do { // 通过在开启列表中找到F值最小的点作为当前点 Position currentPos = openList.get(0); for (int i = 0; i < openList.size(); i++) { if (currentPos.F > openList.get(i).F) { currentPos = openList.get(i); } } // 将找到的当前点放到关闭列表中,并从开启列表中删除 closeList.add(currentPos); openList.remove(currentPos); //遍历当前点对应的8个相邻点 for (int i = 0; i < DIREC.length; i++) { int tmpX = currentPos.row + DIREC[i][0]; int tmpY = currentPos.col + DIREC[i][1]; if (tmpX < 0 || tmpX >= map.length || tmpY < 0 || tmpY >= map[0].length) { continue; } //创建对应的点 Position tmpPos = new Position(tmpX, tmpY, calcH(tmpX, tmpY, x2, y2), currentPos); //map中对应的格子中的值为1(障碍), 或对应的点已经在关闭列表中 if (map[tmpX][tmpY] == 1 || closeList.contains(tmpPos)) { continue; } //如果不在开启列表中,则加入到开启列表 if (!openList.contains(tmpPos)) { openList.add(tmpPos); } else { // 如果已经存在开启列表中,则用G值考察新的路径是否更好,如果该路径更好,则把父节点改成当前格并从新计算FGH Position prePos = null; for (Position pos : openList) { if (pos.row == tmpX && pos.col == tmpY) { prePos = pos; break; } } if (tmpPos.G < prePos.G) { prePos.setFaPos(currentPos); } } } // 判断终点是否在开启列表中 for (Position tpos : openList) { if (tpos.row == x2 && tpos.col == y2) { termPos = tpos; findFlag = true; break; } } } while(openList.size() != 0); if(!findFlag) { System.out.println("no valid path!"); return; } Stack<String> resStack = new Stack<String>(); String pattern = "(%d, %d)"; if (termPos != null) { resStack.push(String.format(pattern, termPos.row, termPos.col)); while(termPos.fa != null) { termPos = termPos.fa; resStack.push(String.format(pattern, termPos.row, termPos.col)); } } StringBuilder sb = new StringBuilder(); while (!resStack.empty()) { sb.append(resStack.pop()); if (!resStack.empty()) { sb.append(" -> "); } } System.out.println(sb.toString()); } /** * 计算某个格子的H值 * @param x * @param y * @param tx 终点的x值 * @param ty 终点的y值 * @return */ private static int calcH(int x, int y, int tx, int ty) { int diff = Math.abs(x - tx) + Math.abs(y - ty); return diff * 10; } static class Position { public int F; public int G; public int H; public Position fa; public int row; public int col; public Position() { } public Position(int row, int col, int H) { this(row, col, H, null); } public Position(int row, int col, int H, Position pos) { this.H = H; this.row = row; this.col = col; this.fa = pos; this.G = calcG(); this.F = G + H; } /** * 计算某个点到起始点的代价G * @return */ private int calcG() { if (fa == null) return 0; if (fa.row != this.row && fa.col != this.col) { return 14 + fa.G; } return 10 + fa.G; } public void setFaPos(Position pos) { this.fa = pos; this.G = calcG(); this.F = G + H; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (!(obj instanceof Position)) { return false; } Position pos = (Position) obj; return this.row == pos.row && this.col == pos.col; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + row; result = prime * result + col; return result; } } }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树