A Brief Introduction About A-star Pathfinding Algorithm For Beginners

      英文题目,汉语内容,有点挂羊头卖狗肉的嫌疑,不过请不要打击我这颗想学好英语的心。当了班主任我才发现大一18本书,11本是英语的,能多用两句英语就多用,个人认为这样也是积累的一种方法。

     Thanks open source pioneers dedicated to computer science especially A*.

一、算法简介

     为什么写这个,以前学长就用这个结合MFC做了个小游戏,分为三个等级“弱智,一般,大神”,分别采用不同算法来寻找迷宫出口,其中大神就是采用A*算法,当时感觉好神奇啊。前几天网上看到有人问A*算法,我就研究了下。下面的这部分内容估计奔走在各大高校的人工智能课上(国外的一片算法分析),很明显,笔者也不能免俗。

      我知道下面不属于学术不端(没发表,结合自己的理解重新表达),现在就一起共享大神的作品吧(从图中可以看出并不是所有点都搜索一遍才找到了路径,给图片的目的是为了直观理解,以后忘记的话,看看图片也就记起来算法了,作为一名中共党员,笔者只信仰马克思主义,实践检验真理的唯一标准)。

      我们假设某个人要从A点到达B点,而一堵墙把这两个点隔开了,如下图所示,绿色部分代表起点A,红色部分代表终点B,蓝色方块部分代表之间的墙。

                                          

                          

      你首先会注意到我们把这一块搜索区域分成了一个一个的方格(如果地图特别大,类似稀疏矩阵的话就要结合数据结构的稀疏矩阵了,划分大块,不过没遇到过例子,不会),如此这般,使搜索区域简单化,正是寻找路径的第一步。这种方法将我们的搜索区域简化成了一个普通的二维数组。数组中的每一个元素表示对应的一个方格,该方格的状态被标记为可通过的和不可通过的。通过找出从A点到B点所经过的方格,就能得到AB之间的路径。当路径找出来以后,这个人就可以从一个格子中央移动到另一个格子中央,直到抵达目的地。  这些格子的中点叫做节点。当你在其他地方看到有关寻找路径的东西时,你会经常发现人们在讨论节点。为什么不直接把它们称作方格呢?因为你不一定要把你的搜索区域分隔成方块(感觉高大上),矩形、六边形或者其他任何形状都可以。况且节点还有可能位于这些形状内的任何一处呢(这句不懂,莫非是每个大块提前做一些预处理)?在中间、靠着边,或者什么的。我们就用这种设定,因为毕竟这是最简单的情况。

      开始搜索,当我们把搜索区域简化成一些很容易操作的节点后,下一步就要构造一个搜索来寻找最短路径。在A*算法中,我们从A点开始,依次检查它的相邻节点,然后照此继续并向外扩展直到找到目的地。 从A点开始,将A点加入一个专门存放待检验的方格的“开放列表”中。这个开放列表有点像一张购物清单。当前这个列表中只有一个元素(个人感觉可以不加),但一会儿将会有更多。列表中包含的方格可能会是你要途经的方格,也可能不是。总之,这是一个包含待检验方格的列表。检查起点A相邻的所有可达的或者可通过的方格,不用管墙啊,水啊,或者其他什么无效地形,把它们也都加到开放列表中(这句话我很不认同,可能我理解错了,看我代码你会发现,我最外圈加了一圈1,表示墙壁,遇到墙壁就继续找其他相邻节点,并没有加入openTable)。对于每一个相邻方格,将点A保存为它们的“父方格”(类似最短路径算法打印路径,当然你可以选择严蔚敏老师的三维数组保存路径法,关于SP问题请参考笔者的(包括四大算法)http://www.cnblogs.com/hxsyl/p/3270401.html)。当我们要回溯路径的时候,父方格是一个很重要的元素。从开放列表中去掉方格A,并把A加入到一个“封闭列表”中。封闭列表存放的是你现在不用再去考虑的方格(说的很清楚,只是暂时不用考虑,如果不进行二次判断(指的是重新拿出来这个点来更新周边)的话,干嘛要closeTable,所以笔者认为不要光看理论,想一下实际情况,很多问题就会豁然开朗)。此时你将得到如图所示的样子。在这张图中,中间深绿色的方格是你的起始方格,所有相邻方格目前都在开放列表中,并且以亮绿色描边。每个相邻方格有一个灰色的指针指向它们的父方格,即起始方格。然后排序找到G最小的点作为下次起点。

      下面还有很多,感觉不必赘述,随便百度一下都有的。

二、算法描述

  1: //这段伪代码可以看出个大概,但是不完全,知道意思就行
  2: while (Open表非空)  {
  3:   从Open中取得一个节点X,并从OPEN表中删除。
  4:   if (X是目标节点)   {
  5:     求得路径PATH;
  6:     返回路径PATH;
  7:   }
  8:   for (每一个X的子节点Y)   {
  9:     if (Y不在OPEN表和CLOSE表中)    {
 10:       求Y的估价值;
 11:       并将Y插入OPEN表中;
 12:     }else if (Y在OPEN表中)    {
 13:       if (Y的估价值小于OPEN表的估价值)
 14:         更新OPEN表中的估价值;
 15:       }
 16:     else {//Y在CLOSE表中
 17:       if (Y的估价值小于CLOSE表的估价值)     {
 18:         更新CLOSE表中的估价值;
 19:         从CLOSE表中移出节点,并放入OPEN表中;
 20:       }
 21:     }
 22:   }
 23:   将X节点插入CLOSE表中;
 24:   按照估价值将OPEN表中的节点排序;
 25: }

三、算法Java实现

      看了两天,感觉很简单,真正写的时候你会发现有多蛋疼,如果你是个爱思考的人,估计问题更多。

  1: package util;
  2:
  3: import java.util.ArrayList;
  4: import java.util.Collections;
  5: import java.util.Stack;
  6:
  7: public class AstarPathFind {
  8:   // 前四个是上下左右,后四个是斜角
  9:   public final static int[] dx = { 0, -1, 0, 1, -1, -1, 1, 1 };
 10:   public final static int[] dy = { -1, 0, 1, 0, 1, -1, -1, 1 };
 11:
 12:   // 最外圈都是1表示不可通过
 13:   final static public int[][] map = {
 14:       { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
 15:       { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
 16:       { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
 17:       { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
 18:       { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
 19:       { 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1 },
 20:       { 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
 21:       { 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
 22:       { 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
 23:       { 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1 },
 24:       { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
 25:       { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
 26:       { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
 27:       { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
 28:       { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } };
 29:
 30:   public static void main(String[] args) {
 31:     // TODO Auto-generated method stub
 32:     Point start = new Point(1, 1);
 33:     Point end = new Point(10, 13);
 34:     /*
 35:      * 第一个问题:起点FGH需要初始化吗?
 36:      * 看参考资料的图片发现不需要
 37:      */
 38:     Stack<Point> stack = printPath(start, end);
 39:     if(null==stack) {
 40:       System.out.println("不可达");
 41:     }else {
 42:       while(!stack.isEmpty()) {
 43:         //输出(1,2)这样的形势需要重写toString
 44:         System.out.print(stack.pop()+" -> ");
 45:       }
 46:       System.out.println();
 47:     }
 48:
 49:   }
 50:
 51:   public static Stack<Point> printPath(Point start, Point end) {
 52:
 53:     /*
 54:      * 不用PriorityQueue是因为必须取出存在的元素
 55:      */
 56:     ArrayList<Point> openTable = new ArrayList<Point>();
 57:     ArrayList<Point> closeTable = new ArrayList<Point>();
 58:     openTable .clear();
 59:     closeTable.clear();
 60:     Stack<Point> pathStack = new Stack<Point>();
 61:     start.parent = null;
 62:     //该点起到转换作用,就是当前扩展点
 63:     Point currentPoint = new Point(start.x, start.y);
 64:     //closeTable.add(currentPoint);
 65:     boolean flag = true;
 66:
 67:     while(flag) {
 68:       for (int i = 0; i < 8; i++) {
 69:         int fx = currentPoint.x + dx[i];
 70:         int fy = currentPoint.y + dy[i];
 71:         Point tempPoint = new Point(fx,fy);
 72:         if (map[fx][fy] == 1) {
 73:           // 由于边界都是1中间障碍物也是1,,这样不必考虑越界和障碍点扩展问题
 74:           //如果不设置边界那么fx >=map.length &&fy>=map[0].length判断越界问题
 75:           continue;
 76:         } else {
 77:           if(end.equals(tempPoint)) {
 78:             flag = false;
 79:             //不是tempPoint,他俩都一样了此时
 80:             end.parent = currentPoint;
 81:             break;
 82:           }
 83:           if(i<4) {
 84:             tempPoint.G = currentPoint.G + 10;
 85:           }else {
 86:             tempPoint.G = currentPoint.G + 14;
 87:           }
 88:           tempPoint.H = Point.getDis(tempPoint,end);
 89:           tempPoint.F = tempPoint.G + tempPoint.H;
 90:           //因为重写了equals方法,所以这里包含只是按equals相等包含
 91:           //这一点是使用java封装好类的关键
 92:           if(openTable.contains(tempPoint)) {
 93:             int pos = openTable.indexOf(tempPoint );
 94:             Point temp = openTable.get(pos);
 95:             if(temp.F > tempPoint.F) {
 96:               openTable.remove(pos);
 97:               openTable.add(tempPoint);
 98:               tempPoint.parent = currentPoint;
 99:             }
100:           }else if(closeTable.contains(tempPoint)){
101:             int pos = closeTable.indexOf(tempPoint );
102:             Point temp = closeTable.get(pos);
103:             if(temp.F > tempPoint.F) {
104:               closeTable.remove(pos);
105:               openTable.add(tempPoint);
106:               tempPoint.parent = currentPoint;
107:             }
108:           }else {
109:             openTable.add(tempPoint);
110:             tempPoint.parent = currentPoint;
111:           }
112:
113:         }
114:       }//end for
115:
116:       if(openTable.isEmpty()) {
117:         return null;
118:       }//无路径
119:       if(false==flag) {
120:         break;
121:       }//找到路径
122:       openTable.remove(currentPoint);
123:       closeTable.add(currentPoint);
124:       Collections.sort(openTable);
125:       currentPoint = openTable.get(0);
126:
127:     }//end while
128:     Point node = end;
129:     while(node.parent!=null) {
130:       pathStack.push(node);
131:       node = node.parent;
132:     }
133:     return pathStack;
134:   }
135: }
136:
137: class Point implements Comparable<Point>{
138:   int x;
139:   int y;
140:   Point parent;
141:   int F, G, H;
142:
143:   public Point(int x, int y) {
144:     super();
145:     this.x = x;
146:     this.y = y;
147:     this.F = 0;
148:     this.G = 0;
149:     this.H = 0;
150:   }
151:
152:   @Override
153:   public int compareTo(Point o) {
154:     // TODO Auto-generated method stub
155:     return this.F  - o.F;
156:   }
157:
158:   @Override
159:   public boolean equals(Object obj) {
160:     Point point = (Point) obj;
161:     if (point.x == this.x && point.y == this.y)
162:       return true;
163:     return false;
164:   }
165:
166:   public static int getDis(Point p1, Point p2) {
167:     int dis = Math.abs(p1.x - p2.x) * 10 + Math.abs(p1.y - p2.y) * 10;
168:     return dis;
169:   }
170:
171:   @Override
172:   public String toString() {
173:     return "(" + this.x + "," + this.y + ")";
174:   }
175:
176: }
177: /*
178: 成功了,我在想找到的一定是最佳路线么,别告诉我因为每次取最佳点,我的意思是可能8次每循环完就break了,男刀这是不同路径的最佳路线
179: */
180: 

四、结束语

      大神提到,不管地图差异的话,主要是排序耽误时间,可考虑二叉堆(大神和我想法一样,哈哈),实际就是堆排序(不太清楚的请参考博主这篇博文http://www.cnblogs.com/hxsyl/p/3244756.html),不过这都不是咱么考虑的问题啦。。。。。好啦,洗洗该去上听力课了。

时间: 2024-10-06 10:12:23

A Brief Introduction About A-star Pathfinding Algorithm For Beginners的相关文章

A Gentle Introduction to the Gradient Boosting Algorithm for Machine Learning

A Gentle Introduction to the Gradient Boosting Algorithm for Machine Learning by Jason Brownlee on September 9, 2016 in XGBoost 0 0 0 0 Gradient boosting is one of the most powerful techniques for building predictive models. In this post you will dis

笔试算法题(48):简介 - A*搜索算法(A Star Search Algorithm)

A*搜索算法(A Star Search Algorithm) A*算法主要用于在二维平面上寻找两个点之间的最短路径.在从起始点到目标点的过程中有很多个状态空间,DFS和BFS没有任何启发策略所以穷举所有的状 态空间,不适合仅需对局部进行搜索的应用.启发式搜索的关键在于:当前节点在选择下一步节点的时候,可以通过一个启发函数进行选择,选择到达终点代价最小 的节点作为下一步节点.A*的启发函数构造为: f(n)=g(n)+h(n) f(n)是可选的下一个节点的代 价,g(n)表示从start点到n点

A* Pathfinding Algorithm

Given? an ?n? x ?n ?grid ?with ?a ?person? and ?obstacles, ?how? would ?you ?find ?a? path ?for ?the? person? to? a? particular ?destination?? ?The ?person? is ?permitted? to? move ?left,?right,? up,? and? down. Sample Input: ............ ....oo..d..

如何在Cocos2D游戏中实现A*寻路算法(一)

大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流之用,请勿进行商业用途.同时,转载时不要移除本申明.如产生任何纠纷,均与本博客所有人.发表该翻译稿之人无任何关系.谢谢合作! 该篇博客由iOS课程团队的Johann Fradj发布,他现在是一个全职开发iOS的开发者.他是Hot Apps Factory(其是App Cooker的创造者)的共同创建

关于图算法 &amp; 图分析的基础知识概览

网址:https://learning.oreilly.com/library/view/graph-algorithms-/9781492060116/ 你肯定没有读过这本书,因为这本书的发布日期是2019年5月.本文会覆盖该书的大部分内容,读完这篇,你能够了解图算法的基本概念.关于此书,作为市面上为数不多的面向数据科学应用的图算法书籍,写的比较全面系统和易懂.当然,书在细节上的提高空间还有很多.今天内容很多,坐稳~ 目录 图算法 & 图分析 图基础知识 连通图与非连通图 未加权图与加权图 有

Calculus on Computational Graphs: Backpropagation

Calculus on Computational Graphs: Backpropagation Introduction Backpropagation is the key algorithm that makes training deep models computationally tractable. For modern neural networks, it can make training with gradient descent as much as ten milli

计算机必读书籍

漫长的三年过去了,我们摸爬滚打,没有指路的明灯.我也在摸索中走了不少的弯路,向我的软件班的同学引荐别人推荐几本好书(我也是在查漏补缺),希望有志者能少走些弯路. 一. 科学哲学和管理哲学[1] “程序开发心理学”(The Psychology of Computer Programming : Silver Anniversary Edition)[2] “系统化思维导论”(An Introduction to Systems Thinking, Silver Anniversary Editi

awesome-algorithms

Awesome Algorithms A curated list of awesome places to learn and/or practice algorithms.Inspired by awesome-awesomeness and all the other awesome Awesome libraries. If you want to contribute, please read the [contribution guidelines] (https://github.

The Independent JPEG Group&#39;s JPEG software Android源码中 JPEG的ReadMe文件

The Independent JPEG Group's JPEG software========================================== README for release 6b of 27-Mar-1998==================================== This distribution contains the sixth public release of the Independent JPEGGroup's free JPEG