英文題目,漢語內容,有點掛羊頭賣狗肉的嫌疑,不過請不要打擊我這顆想學好英語的心。當了班主任我才發現大一18本書,11本是英語的,能多用兩句英語就多用,我的認爲這樣也是積累的一種方法。html
Thanks open source pioneers dedicated to computer science especially A*.java
1、算法簡介node
爲何寫這個,之前學長就用這個結合MFC作了個小遊戲,分爲三個等級「弱智,通常,大神」,分別採用不一樣算法來尋找迷宮出口,其中大神就是採用A*算法,當時感受好神奇啊。前幾天網上看到有人問A*算法,我就研究了下。下面的這部份內容估計奔走在各大高校的人工智能課上(國外的一片算法分析),很明顯,筆者也不能免俗。算法
我知道下面不屬於學術不端(沒發表,結合本身的理解從新表達),如今就一塊兒共享大神的做品吧(從圖中能夠看出並非全部點都搜索一遍才找到了路徑,給圖片的目的是爲了直觀理解,之後忘記的話,看看圖片也就記起來算法了,做爲一名中共黨員,筆者只信仰馬克思主義,實踐檢驗真理的惟一標準)。數組
咱們假設某我的要從A點到達B點,而一堵牆把這兩個點隔開了,以下圖所示,綠色部分表明起點A,紅色部分表明終點B,藍色方塊部分表明之間的牆。數據結構
你首先會注意到咱們把這一塊搜索區域分紅了一個一個的方格(若是地圖特別大,相似稀疏矩陣的話就要結合數據結構的稀疏矩陣了,劃分大塊,不過沒遇到過例子,不會),如此這般,使搜索區域簡單化,正是尋找路徑的第一步。這種方法將咱們的搜索區域簡化成了一個普通的二維數組。數組中的每個元素表示對應的一個方格,該方格的狀態被標記爲可經過的和不可經過的。經過找出從A點到B點所通過的方格,就能獲得AB之間的路徑。當路徑找出來之後,這我的就能夠從一個格子中央移動到另外一個格子中央,直到抵達目的地。 這些格子的中點叫作節點。當你在其餘地方看到有關尋找路徑的東西時,你會常常發現人們在討論節點。爲何不直接把它們稱做方格呢?由於你不必定要把你的搜索區域分隔成方塊(感受高大上),矩形、六邊形或者其餘任何形狀均可以。何況節點還有可能位於這些形狀內的任何一處呢(這句不懂,莫非是每一個大塊提早作一些預處理)?在中間、靠着邊,或者什麼的。咱們就用這種設定,由於畢竟這是最簡單的狀況。ide
開始搜索,當咱們把搜索區域簡化成一些很容易操做的節點後,下一步就要構造一個搜索來尋找最短路徑。在A*算法中,咱們從A點開始,依次檢查它的相鄰節點,而後照此繼續並向外擴展直到找到目的地。 從A點開始,將A點加入一個專門存放待檢驗的方格的「開放列表」中。這個開放列表有點像一張購物清單。當前這個列表中只有一個元素(我的感受能夠不加),但一下子將會有更多。列表中包含的方格可能會是你要途經的方格,也可能不是。總之,這是一個包含待檢驗方格的列表。檢查起點A相鄰的全部可達的或者可經過的方格,不用管牆啊,水啊,或者其餘什麼無效地形,把它們也都加到開放列表中(這句話我很不認同,可能我理解錯了,看我代碼你會發現,我最外圈加了一圈1,表示牆壁,遇到牆壁就繼續找其餘相鄰節點,並無加入openTable)。對於每個相鄰方格,將點A保存爲它們的「父方格」(相似最短路徑算法打印路徑,固然你能夠選擇嚴蔚敏老師的三維數組保存路徑法,關於SP問題請參考筆者的(包括四大算法)http://www.cnblogs.com/hxsyl/p/3270401.html)。當咱們要回溯路徑的時候,父方格是一個很重要的元素。從開放列表中去掉方格A,並把A加入到一個「封閉列表」中。封閉列表存放的是你如今不用再去考慮的方格(說的很清楚,只是暫時不用考慮,若是不進行二次判斷(指的是從新拿出來這個點來更新周邊)的話,幹嗎要closeTable,因此筆者認爲不要光看理論,想一下實際狀況,不少問題就會豁然開朗)。此時你將獲得如圖所示的樣子。在這張圖中,中間深綠色的方格是你的起始方格,全部相鄰方格目前都在開放列表中,而且以亮綠色描邊。每一個相鄰方格有一個灰色的指針指向它們的父方格,即起始方格。而後排序找到G最小的點做爲下次起點。this
下面還有不少,感受沒必要贅述,隨便百度一下都有的。人工智能
2、算法描述spa
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: }
3、算法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:
4、結束語
大神提到,無論地圖差別的話,主要是排序耽誤時間,可考慮二叉堆(大神和我想法同樣,哈哈),實際就是堆排序(不太清楚的請參考博主這篇博文http://www.cnblogs.com/hxsyl/p/3244756.html),不過這都不是咱麼考慮的問題啦。。。。。好啦,洗洗該去上聽力課了。