一时兴起,写了个寻路代码

看到一个面试题,是有关寻路的,于是想练练手,自己也写一个。

把地图坐标设计为二维数据,坐标点的值代表不同意义。

先上代码:

  1 import java.util.ArrayList;
  2 import java.util.Collections;
  3 import java.util.Comparator;
  4 import java.util.List;
  5 
  6 public class FindLine {
  7     // 测试数据,0代表可通的路,1代表墙,5代表起点或终点
  8     public static int[][] map = { 
  9             { 0, 0, 0, 0, 0, 0 }, 
 10             { 0, 1, 0, 1, 0, 0 },
 11             { 0, 0, 5, 0, 1, 0 },
 12             { 0, 0, 0, 1, 0, 0 },
 13             { 0, 1, 1, 5, 0, 1 },
 14             { 0, 0, 1, 0, 0, 0 } };
 15 
 16     // 方向 = 0,1,2,3 上右下左
 17     public static int[][] move = { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 } }; // 上,右,下,左
 18     // 记录已经查询过路径
 19     public static int[][] used = { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 },
 20             { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 },
 21             { 0, 0, 0, 0, 0, 0 } };
 22 
 23     /**
 24      * @author Huang
 25      * @return void
 26      */
 27 
 28     public static void main(String[] args) {
 29 
 30         int[] o1 = { 2, 2 }; // 起点
 31         int[] o2 = { 4, 3 }; // 终点
 32         if (eq(o1, o2)) {
 33             used[o1[0]][o1[1]] = 1;
 34             runLineOld.add(o1);
 35             if (count(o1, o2)) {
 36                 used[o2[0]][o2[1]] = 1;
 37                 runLineOld.add(o2);
 38                 reline();
 39                 System.out.println();
 40                 System.out.println("寻路记录的点(用2来表示)");
 41                 for (int i = 0; i < used.length; i++) {
 42                     for (int j = 0; j < used[i].length; j++) {
 43                         System.out.print(used[i][j] + "  ");
 44                     }
 45                     System.out.println();
 46                 }
 47                 
 48                 System.out.println("初始路径");
 49                 for (int[] r : runLineOld) {
 50                     System.out.print("[" + r[0] + "," + r[1] + "],");
 51                 }
 52                 System.out.println();
 53                 System.out.println("优化后路径");
 54                 for (int[] r : runLineNew) {
 55                     System.out.print("[" + r[0] + "," + r[1] + "],");
 56                 }
 57                 
 58                 
 59             }
 60         }
 61 
 62     }
 63 
 64     // 检查是否相等
 65     public static boolean eq(int[] o1, int[] o2) {
 66         return map[o1[0]][o1[1]] == map[o2[0]][o2[1]];
 67     }
 68 
 69     
 70     static List<int[]> runLineOld = new ArrayList<>(); // 初始路径
 71     static List<int[]> runLineNew = new ArrayList<>(); // 优化路径
 72 
 73     // 计算路径
 74     public static boolean count(int[] o1, int[] o2) {
 75         if (isNear(o1, o2)) {
 76             System.out.print("[" + o2[0] + "," + o2[1] + "],");
 77             return true; // yes
 78         }
 79 
 80         int[] line = findLine(o1);
 81         if (line.length == 0) {
 82             return false;// no ;
 83         }
 84 
 85         List<LineRate> lr = countRate(o1, line, o2);
 86         Collections.sort(lr, new Comparator<LineRate>() {
 87             @Override
 88             public int compare(LineRate o1, LineRate o2) {
 89                 if (o1.getR() > o2.getR()) {
 90                     return 1;
 91                 } else if (o1.getR() < o2.getR()) {
 92                     return -1;
 93                 }
 94                 return 0;
 95             }
 96         });
 97 
 98         boolean find = false;
 99         for (int i = 0; i < lr.size(); i++) {
100             int[] ot = new int[2];
101             ot[0] = o1[0] + move[lr.get(i).getF()][0];
102             ot[1] = o1[1] + move[lr.get(i).getF()][1];
103             if (used[ot[0]][ot[1]] == 1) {
104                 continue;
105             }
106             used[ot[0]][ot[1]] = 1;
107             runLineOld.add(ot);
108             System.out.print("[" + ot[0] + "," + ot[1] + "],");
109             if (count(ot, o2)) {
110                 // yes
111                 find = true;
112                 break;
113             } else {
114                 used[ot[0]][ot[1]] = 2;// 此路不通
115                 System.out.print("|");
116                 runLineOld.remove(runLineOld.size() - 1);
117                 continue;
118             }
119         }
120         return find;
121 
122     }
123 
124     public static boolean isNear(int[] o1, int[] o2) {
125         if (o1[0] == o2[0] && Math.abs(o1[1] - o2[1]) == 1) {
126             return true;
127         } else if (o1[1] == o2[1] && Math.abs(o1[0] - o2[0]) == 1) {
128             return true;
129         } else {
130             return false;
131         }
132     }
133 
134     // 找出可用路径
135     public static int[] findLine(int[] o1) {
136 
137         List<Integer> cl = new ArrayList<>();
138 
139         for (int i = 0; i < 4; i++) {
140             if (checkUse(o1, i) == 1) {
141                 cl.add(i);
142             }
143         }
144         int[] f = new int[cl.size()];
145         for (int i = 0; i < f.length; i++) {
146             f[i] = cl.get(i);
147         }
148         return f;
149 
150     }
151 
152     // 检查该位置是否可用,1是,0否
153     public static int checkUse(int[] o1, int f) {
154 
155         int xt1 = o1[0] + move[f][0];
156         int yt1 = o1[1] + move[f][1];
157         if (xt1 > -1 && xt1 < map[0].length && yt1 > -1 && yt1 < map.length
158                 && used[xt1][yt1] == 0) {
159             if (map[xt1][yt1] == 0) {
160                 return 1;
161             }
162         }
163         return 0;
164     }
165 
166     // 计算权重
167     public static List<LineRate> countRate(int[] ot, int[] f, int[] o2) {
168 
169         // r = g + h , g = 10 , h = |x2 - x1 |+ |y2 - y1|
170         int g = 10;
171         List<LineRate> list = new ArrayList<>();
172         for (int i = 0; i < f.length; i++) {
173             int otx = ot[0] + move[f[i]][0];
174             int oty = ot[1] + move[f[i]][1];
175             int r = Math.abs(o2[0] - otx) + Math.abs(o2[1] - oty) + g;
176             LineRate lr = new LineRate();
177             lr.setF(f[i]);
178             lr.setR(r);
179             list.add(lr);
180         }
181         return list;
182 
183     }
184 
185     // 线路与权重
186     static class LineRate {
187         int f;
188         int r;
189 
190         public int getF() {
191             return f;
192         }
193 
194         public void setF(int f) {
195             this.f = f;
196         }
197 
198         public int getR() {
199             return r;
200         }
201 
202         public void setR(int r) {
203             this.r = r;
204         }
205     }
206 
207     // 修正路径
208     public static void reline() {
209 
210         List<Integer> record = new ArrayList<>();
211         int len = runLineOld.size() - 1;
212         int i = 0;
213         int j = len;
214         record.add(i);
215         runLineNew.add(runLineOld.get(i));
216         while (true) {
217             while (i < j && !isNear(runLineOld.get(i), runLineOld.get(j))) {
218                 j--;
219             }
220             if (i < j) { // 找到可优化的路径
221                 i = j;
222                 runLineNew.add(runLineOld.get(i));
223                 j = len;
224             } else if (i == len) {
225                 break;
226             } else if (i == j) {
227                 i++;
228             }
229         }
230     }
231 
232 }

运行结果:

[2,3],|[3,2],[3,1],[2,1],[2,0],[3,0],[4,0],[5,0],[5,1],||||[1,0],[0,0],[0,1],[0,2],[0,3],[0,4],[1,4],[1,5],[2,5],[3,5],[3,4],[4,4],[4,3],
寻路记录的点(2寻过的路且不通,1寻找的路径,0墙)
1  1  1  1  1  0 
1  0  0  0  1  1 
1  1  1  2  0  1 
2  1  1  0  1  1 
2  0  0  1  1  0 
2  2  0  0  0  0 
初始路径
[2,2],[3,2],[3,1],[2,1],[2,0],[1,0],[0,0],[0,1],[0,2],[0,3],[0,4],[1,4],[1,5],[2,5],[3,5],[3,4],[4,4],[4,3],
优化后路径
[2,2],[2,1],[2,0],[1,0],[0,0],[0,1],[0,2],[0,3],[0,4],[1,4],[1,5],[2,5],[3,5],[3,4],[4,4],[4,3],

思路:

深度优先寻路,再采用A*算法中的权重来优先选择格子,遇到墙时,就选择权重第二小的,依此进行....

由于是深度优先,得到的路径并不是最估的,然后再进行路径优化,得到最后的结果。

PS:深度优先,再优化路径,这感觉在墙比较多时会高效些,广度优先,我估计不用再优化路径这步操作了,但计算量会多很多。

原文地址:https://www.cnblogs.com/hellohuang/p/find_line.html