看到一个面试题,是有关寻路的,于是想练练手,自己也写一个。
把地图坐标设计为二维数据,坐标点的值代表不同意义。
先上代码:
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:深度优先,再优化路径,这感觉在墙比较多时会高效些,广度优先,我估计不用再优化路径这步操作了,但计算量会多很多。