最短路径A*算法原理及java代码实现(看不懂是我的失败)
A*算法
1.2 Dijkstra算法与最佳优先搜索
Dijkstra算法从物体所在的初始点開始,訪问图中的结点。它迭代检查待检查结点集中的结点,并把和该结点最靠近的尚未检查的结点增加待检查结点集。该结点集从初始结点向外扩展,直到到达目标结点。Dijkstra算法保证能找到一条从初始点到目标点的最短路径,仅仅要全部的边都有一个非负的代价值。(我说“最短路径”是由于常常会出现很多差点儿相同短的路径。)在下图中,粉红色的结点是初始结点,蓝色的是目标点,而类菱形的有色区域(注:原文是teal
areas)则是Dijkstra算法扫描过的区域。颜色最淡的区域是那些离初始点最远的,因而形成探測过程(exploration)的边境(frontier):
下图同样颜色的格子代表起点到达这些格子的代价是一样的,颜色越浅代表到达目标所须要的代价越大,Dijkstra算法均衡的向四面八方扩张,被扩张的每个格子都会记住它前一个消耗最少的那个格子,直到扩张区域包括目标点
最佳优先搜索(BFS)算法依照类似的流程执行,不同的是它可以评估(称为启示式的)随意结点到目标点的代价。与选择离初始结点近期的结点不同的是,它选择离目标近期的结点。BFS不能保证找到一条最短路径。然而,它比Dijkstra算法快的多,由于它用了一个启示式函数(heuristic
function)高速地导向目标结点。比如,假设目标位于出发点的南方,BFS将趋向于导向南方的路径。在以下的图中,越黄的结点代表越高的启示式值(移动到目标的代价高),而越黑的结点代表越低的启示式值(移动到目标的代价低)。这表明了与Dijkstra 算法相比,BFS执行得更快。
贪心算法:颜色同样的格子代表这些格子在理想状态下(没有障碍物的情况下)直线到达目标点的代价是一样的,从起点不停的像终点扩张,扩张的时候会记住前一个最小理想代价的格子假设碰到障碍物它会又一次选择新的理想代价最少的那一个格子直到到达目标格子
然而,这两个样例都不过最简单的情况——地图中没有障碍物,最短路径是直线的。如今我们来考虑前边描写叙述的凹型障碍物。Dijkstra算法执行得较慢,但确实能保证找到一条最短路径:
还有一方面,BFS执行得较快,可是它找到的路径明显不是一条好的路径:
问题在于BFS是基于贪心策略的,它试图向目标移动虽然这不是正确的路径。因为它只考虑到达目标的代价,而忽略了当前已花费的代价,于是虽然路径变得非常长,它仍然继续走下去。
结合两者的长处不是更好吗?1968年发明的A*算法就是把启示式方法(heuristic
approaches)如BFS,和常规方法如Dijsktra算法结合在一起的算法。有点不同的是,类似BFS的启示式方法常常给出一个近似解而不是保证最佳解。然而,虽然A*基于无法保证最佳解的启示式方法,A*却能保证找到一条最短路径。
1.3 A*算法
我将集中讨论A*算法。A*是路径搜索中最受欢迎的选择,由于它相当灵活,而且能用于多种多样的情形之中。
和其他的图搜索算法一样,A*潜在地搜索图中一个非常大的区域。和Dijkstra一样,A*能用于搜索最短路径。和BFS一样,A*能用启示式函数(注:原文为heuristic)引导它自己。在简单的情况中,它和BFS一样快。
在凹型障碍物的样例中,A*找到一条和Dijkstra算法一样好的路径:
成功的秘决在于,它把Dijkstra算法(靠近初始点的结点)和BFS算法(靠近目标点的结点)的信息块结合起来。在讨论A*的标准术语中,g(n)表示从初始结点到随意结点n的代价,h(n)表示从结点n到目标点的启示式评估代价(heuristic
estimated cost)。在上图中,yellow(h)表示远离目标的结点而teal(g)表示远离初始点的结点。当从初始点向目标点移动时,A*权衡这两者。每次进行主循环时,它检查f(n)最小的结点n,当中f(n)
= g(n) + h(n)。
终于获取最佳路径(1,2)->(2,2)->(3,3)->(4,2)
图二
package astar; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set; /**
*
* @author hjn
* @version 1.0 2015-03-11
*
*/
public class AStar implements IMove { public static final int MOVE_TETN = 10;
public static final int MOVE_SIDE = 14;
public static final int LENGHT = 10;
/* 打开的列表 */
Map<String, Point> openMap = new HashMap<String, Point>();
/* 关闭的列表 */
Map<String, Point> closeMap = new HashMap<String, Point>();
/* 障碍物 */
Set<Point> barrier;
/* 起点 */
Point startPoint;
/* 终点 */
Point endPoint;
/* 当前使用节点 */
Point currentPoint;
/* 循环次数,为了防止目标不可到达 */
int num = 0;
Point lastPoint; /**
* 获取点1到点1的最佳路径
*/
@Override
public Point move(int x1, int y1, int x2, int y2, Set<Point> barrier) {
num = 0;
this.lastPoint=new Point(x2,y2);
this.barrier = barrier;
this.startPoint = new Point(x1, y1);
Point endPoint=new Point(x2,y2);
this.endPoint = this.getNearPoint(endPoint,endPoint);
this.closeMap.put(startPoint.getKey(), startPoint);
this.currentPoint = this.startPoint;
this.toOpen(x1, y1);
return endPoint;
} /**
* 求亮点间的估算代价,性能由高到低 启示函数一(曼哈顿距离): (Math.abs(x1 - x2) + Math.abs(y1 - y2)) *
* 单位长度 启示函数二(平方的欧几里得距离):((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 -y1))*
* 单位长度 启示函数三(欧几里得距离):(int) Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) *
* (y2 -y1))* 单位长度 启示函数四(对角线距离):Math.max(Math.abs(x1 - x2), Math.abs(y1 -
* y2)) * 单位长度 不用启示函数:0
*
* @param x1
* 点1x轴
* @param y1
* 点1y轴
* @param x2
* 点2x轴
* @param y2
* 点2y轴
* @return
*/
private int getGuessLength(int x1, int y1, int x2, int y2) {
//return ((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 -y1))* AStar.LENGHT;
return (Math.abs(x1 - x2) + Math.abs(y1 - y2)) * AStar.LENGHT;
// return Math.max(Math.abs(x1 - x2), Math.abs(y1 - y2)) * AStar.LENGHT;
// return 0;
} /**
* 把该节点相邻点增加打开的列表
*
* @param x
* @param y
*/
private void toOpen(int x, int y) {
this.addOpenPoint(new Point(x - 1, y), AStar.MOVE_TETN);
this.addOpenPoint(new Point(x + 1, y), AStar.MOVE_TETN);
this.addOpenPoint(new Point(x, y - 1), AStar.MOVE_TETN);
this.addOpenPoint(new Point(x, y + 1), AStar.MOVE_TETN);
this.addOpenPoint(new Point(x - 1, y - 1), AStar.MOVE_SIDE);
this.addOpenPoint(new Point(x - 1, y + 1), AStar.MOVE_SIDE);
this.addOpenPoint(new Point(x + 1, y - 1), AStar.MOVE_SIDE);
this.addOpenPoint(new Point(x + 1, y + 1), AStar.MOVE_SIDE);
num++;
if (num <= 4000) {
this.toClose(x, y);
} } /**
* 把该节点相邻点增加关闭的列表
*
* @param x
* @param y
*/
private void toClose(int x, int y) {
List<Point> list = new ArrayList<Point>(openMap.values());
Collections.sort(list, new Comparator<Point>() {
@Override
public int compare(Point o1, Point o2) {
if (o1.fTotal > o2.fTotal) {
return 1;
} else if (o1.fTotal < o2.fTotal) {
return -1;
} else {
return 0;
}
}
});
if (list.size() > 0) {
this.currentPoint = list.get(0);
closeMap.put(this.currentPoint.getKey(), this.currentPoint);
openMap.remove(this.currentPoint.getKey());
if (!currentPoint.equals(endPoint)) {
this.toOpen(this.currentPoint.x, this.currentPoint.y);
} else {
endPoint = this.currentPoint;
}
}
} /**
* 增加开放的点
*
* @param point
* 点
* @param gCost
* 当前点到该点的消耗
* @return
*/
private void addOpenPoint(Point point, int gCost) {
if (point.x < 0 || point.y < 0) {
return;
}
String key = point.getKey();
if (!barrier.contains(point) && !point.equals(this.currentPoint)) {
int hEstimate = this.getGuessLength(point.x, point.y,
this.endPoint.x, this.endPoint.y);
int totalGCost = this.currentPoint.gCost + gCost;
int fTotal = totalGCost + hEstimate;
if (!closeMap.containsKey(key)) {
point.hEstimate = hEstimate;
point.gCost = totalGCost;
point.fTotal = fTotal;
Point oldPoint = openMap.get(key);
if (oldPoint != null) {
if (oldPoint.gCost > totalGCost) {
oldPoint.fTotal = fTotal;
oldPoint.prev = this.currentPoint;
openMap.put(key, oldPoint);
}
} else {
point.prev = this.currentPoint;
openMap.put(key, point);
}
} else {
Point oldPoint = closeMap.get(key);
if (oldPoint != null) {
if ((oldPoint.gCost + gCost) < this.currentPoint.gCost) {
if (this.currentPoint.prev != oldPoint) {
this.currentPoint.fTotal = oldPoint.fTotal + gCost;
this.currentPoint.gCost = oldPoint.gCost + gCost;
this.currentPoint.prev = oldPoint;
}
}
}
}
}
}
Map<String, Point> nearOutMap; public Point getNearPoint(Point point,Point point2) {
if(this.barrier.contains(point)){
nearOutMap = new HashMap<String, Point>();
this.endPoint=point;
this.toNearPoint(point,point2);
List<Point> nearList = new ArrayList<Point>(nearOutMap.values());
Collections.sort(nearList, new Comparator<Point>() {
@Override
public int compare(Point o1, Point o2) {
if (o1.gCost > o2.gCost) {
return 1;
} else if (o1.gCost < o2.gCost) {
return -1;
} else {
return 0;
}
}
});
this.openMap=new HashMap<String,Point>();
this.closeMap=new HashMap<String,Point>();
if (nearList.size() > 0) {
return nearList.get(0);
}else{
return point;
}
}else{
return point;
}
} public void toNearPoint(Point point,Point point2) {
int x = point.x;
int y = point.y;
this.addNearOpenPoint(new Point(x - 1, y),point2);
this.addNearOpenPoint(new Point(x + 1, y),point2);
this.addNearOpenPoint(new Point(x, y - 1),point2);
this.addNearOpenPoint(new Point(x, y + 1),point2);
this.addNearOpenPoint(new Point(x - 1, y - 1),point2);
this.addNearOpenPoint(new Point(x - 1, y + 1),point2);
this.addNearOpenPoint(new Point(x + 1, y - 1),point2);
this.addNearOpenPoint(new Point(x + 1, y + 1),point2);
if(this.nearOutMap.size()==0){
List<Point> list = new ArrayList<Point>(openMap.values());
Collections.sort(list, new Comparator<Point>() {
@Override
public int compare(Point o1, Point o2) {
int l1 = o1.gCost;
int l2 = o2.gCost;
if (l1 > l2) {
return 1;
} else if (l1 < l2) {
return -1;
} else {
return 0;
}
}
});
if (list.size() > 0) {
Point p = list.get(0);
this.closeMap.put(p.getKey(), p);
this.openMap.remove(p.getKey());
this.toNearPoint(list.get(0),point2);
}
}
} private void addNearOpenPoint(Point point,Point point2) {
String key = point.getKey();
int gCost = this.getGuessLength(point.x, point.y, point2.x,
point2.y);
point.gCost = gCost;
if (this.barrier.contains(point)) {
if (!this.openMap.containsKey(key)
&& !this.closeMap.containsKey(key)) {
this.openMap.put(key, point);
}
} else {
this.nearOutMap.put(key, point);
} } public Map<String, Point> getOpenMap() {
return openMap;
} public void setOpenMap(Map<String, Point> openMap) {
this.openMap = openMap;
} public Map<String, Point> getCloseMap() {
return closeMap;
} public void setCloseMap(Map<String, Point> closeMap) {
this.closeMap = closeMap;
} public Set<Point> getBarrier() {
return barrier;
} public void setBarrier(Set<Point> barrier) {
this.barrier = barrier;
} public Point getEndPoint() {
return endPoint;
} public void setEndPoint(Point endPoint) {
this.endPoint = endPoint;
} public Point getStartPoint() {
return startPoint;
} public void setStartPoint(Point startPoint) {
this.startPoint = startPoint;
} }
package astar; import java.util.Set; /**
*
* @author hjn
* @version 1.0 2015-3-11
*
*/
public interface IMove {
/**
* 求点1到点2的合适路线
* @param x1 点1x坐标
* @param y1 点1y坐标
* @param x2 点2x坐标
* @param y2 点2y坐标
* @param barrier 有顺序的路线列表
* @return
*/
Point move(int x1,int y1,int x2,int y2,Set<Point> barrier); }
package astar; public class Point {
int x;
int y;
int gCost;
int hEstimate;
int fTotal;
Point prev;
int level=1; public String getKey(){
return x+"_"+y;
}
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
} public Point(int x, int y, int gCost) {
super();
this.x = x;
this.y = y;
this.gCost = gCost;
} @Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
} @Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Point other = (Point) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
} }
package astar; import java.util.HashSet;
import java.util.Map;
import java.util.Set; import org.junit.Test; public class TestPoint {
@Test
public void test2() {
AStar aStar = new AStar();
Set<Point> barrier = new HashSet<Point>();
/* for (int j = 30; j > 15; j--) {
for (int i = 20; i < 50; i++) {
barrier.add(new Point(j, i)); }
}*/ for (int j = 30; j > 15; j--) {
barrier.add(new Point(j, 20));
}
/*
for (int j = 30; j > 15; j--) {
barrier.add(new Point(j, 50));
}
*/
for (int i = 20; i < 50; i++) {
barrier.add(new Point(30, i));
} for (int i = 20; i < 55; i++) {
barrier.add(new Point(15, i));
}
long start = System.currentTimeMillis();
for (int i = 0; i < 1; i++) {
aStar = new AStar();
aStar.move(10, 25, 28, 40, barrier);
}
long end = System.currentTimeMillis();
System.out.println(end - start);
Set<Point> set = new HashSet<Point>();
Point endPoint = aStar.getEndPoint();
Point startPoint = aStar.getStartPoint();
Map<String, Point> openMap = aStar.getOpenMap();
Map<String, Point> closeMap = aStar.getCloseMap();
set = TestPoint.get(endPoint, set);
/**
* 显示最佳路径
*/
System.out.println(aStar.getEndPoint().getKey());
for (int i = 0; i < 70; i++) {
for (int j = 0; j < 70; j++) {
Point p = new Point(j, i);
if (p.equals(aStar.getEndPoint())) {
System.out.print("o");
} else if (p.equals(startPoint)) {
System.out.print("^");
} else {
if (set.contains(p)) {
System.out.print("@");
} else if (barrier.contains(p)) {
System.out.print("#");
} else {
System.out.print("*");
} }
System.out.print(" ");
}
System.out.println();
} System.out.println("--------------------------------------------------------------------------------------------------------");
/**
* 扫描的范围
*/
for (int i = 0; i < 70; i++) {
for (int j = 0; j < 70; j++) {
Point p = new Point(j, i);
if (p.equals(endPoint)) {
System.out.print("o");
} else if (p.equals(startPoint)) {
System.out.print("^");
} else {
if (openMap.containsKey(p.getKey())) {
System.out.print("%");
} else if (closeMap.containsKey(p.getKey())) {
System.out.print("@");
} else if (barrier.contains(p)) {
System.out.print("#");
} else {
System.out.print("*");
} }
System.out.print(" ");
}
System.out.println();
} } public static Set<Point> get(Point p, Set<Point> set) {
if (p != null) {
set.add(p);
}
Point pp = p.prev;
if (pp != null) {
TestPoint.get(pp, set);
} else {
return set;
}
return set;
}
}
最短路径A*算法原理及java代码实现(看不懂是我的失败)的更多相关文章
- 第二章:排序算法 及其他 Java代码实现
目录 第二章:排序算法 及其他 Java代码实现 插入排序 归并排序 选择排序算法 冒泡排序 查找算法 习题 2.3.7 第二章:排序算法 及其他 Java代码实现 --算法导论(Introducti ...
- 一致性Hash算法原理,java实现,及用途
学习记录: 一致性Hash算法原理及java实现:https://blog.csdn.net/suifeng629/article/details/81567777 一致性Hash算法介绍,原理,及使 ...
- 干货 | 10分钟带你彻底了解column generation(列生成)算法的原理附java代码
OUTLINE 前言 预备知识预警 什么是column generation 相关概念科普 Cutting Stock Problem CG求解Cutting Stock Problem 列生成代码 ...
- JVM原理(Java代码编译和执行的整个过程+JVM内存管理及垃圾回收机制)
转载注明出处: http://blog.csdn.net/cutesource/article/details/5904501 JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.e ...
- 如何做系列(4)-微博URL短网址生成算法原理(java版、php版实现实例)
短网址(Short URL),顾名思义就是在形式上比较短的网址.通常用的是asp或者php转向,在Web 2.0的今天,不得不说,这是一个潮流.目前已经有许多类似服务,借助短网址您可以用简短的网址替代 ...
- Logistic回归分类算法原理分析与代码实现
前言 本文将介绍机器学习分类算法中的Logistic回归分类算法并给出伪代码,Python代码实现. (说明:从本文开始,将接触到最优化算法相关的学习.旨在将这些最优化的算法用于训练出一个非线性的函数 ...
- 第一篇:K-近邻分类算法原理分析与代码实现
前言 本文介绍机器学习分类算法中的K-近邻算法并给出伪代码与Python代码实现. 算法原理 首先获取训练集中与目标对象距离最近的k个对象,然后再获取这k个对象的分类标签,求出其中出现频数最大的标签. ...
- 一致性Hash算法原理及C#代码实现
一.一致性Hash算法原理 基本概念 一致性哈希将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数H的值空间为0-2^32-1(即哈希值是一个32位无符号整形),整个哈希空间环如下: 整个空间按顺 ...
- 第七篇:Logistic回归分类算法原理分析与代码实现
前言 本文将介绍机器学习分类算法中的Logistic回归分类算法并给出伪代码,Python代码实现. (说明:从本文开始,将接触到最优化算法相关的学习.旨在将这些最优化的算法用于训练出一个非线性的函数 ...
随机推荐
- 基于visual Studio2013解决C语言竞赛题之0303最大数
题目 解决代码及点评 这道题考察对条件分支和赋值的灵活应用 正常思维 如果 a>b and a>c 那么a最大 如果b>c and b>a 那么b最大 如果c>a ...
- BZOJ 1665: [Usaco2006 Open]The Climbing Wall 攀岩
题目 1665: [Usaco2006 Open]The Climbing Wall 攀岩 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 197 Sol ...
- 关于jave在oracle驱动下事务提交与回滚问题
一直以来,都觉得Connection假设设置了setAutoCommit(false)后.启动手工事务提交.必须手工进行commit或者rollback才行.今天正好遇到一个问题.结果大跌眼镜. 于是 ...
- Linq实现t-Sql的各种连接
在ORM框架大行其道的今天,对于.net行业的人,想要学好EF,那Linq的学习在势在必行啊.今天总结下平时比较常用的表连接的用法. Inner Join Linq: var list = (from ...
- [Swust OJ 352]--合并果子(贪心+队列模拟)
题目链接:http://acm.swust.edu.cn/problem/352/ Time limit(ms): 1000 Memory limit(kb): 65535 Description ...
- 20150706 js之定时器
对应智能社:09 定时器的使用 开启定时器: setInterval(xxx(),1000);//间隔型 第一个参数为函数,第二个为时间,单位为毫秒 setTimeout(xxx(),1000);// ...
- Flask web应用
Flask web应用 一.介绍 最近开发要用一个测试环境,是这样的Nginx+uwsgi+flask 的一个结构.下面是一些记录,在Centos 系统上使用Flask 架构部署一个简单的Python ...
- jQuery特效手风琴特效 手写手风琴网页特效
今天写一个简单的手风琴效果,不用插件,利用强大的jQuery,写一个手风琴效果. 页面预览,请点击这里预览: 手风琴预览 案例分析: html结构 就是一个大盒子里面放着5个li,每个li的小小是2 ...
- JavaScript:获取系统当前时间,构造格式化的字符串
var getNowFormatDate = function() { var date = new Date(); var seperator1 = "-"; ...
- 使用Maven构建和部署J2EE应用程序的EAR文件
这篇文章.主要是技术上的整理,用来mark一下,用的时候參考. 一.新建项目 新建一个空的Maven Project项目 二.放入依赖 注:ear部署时假设里面有entity,会错误发生.所以不要把e ...