软件工程二人组队开发第一周
小组成员:高达,程超然
项目名称:地铁站搭乘系统
项目目的:能使用户搭乘到最优路线
环境:Mysql(8.0)和Eclipse(jdk1.8)
我的工作是写除了servlet的java代码,使用控制台实现我们想要的功能:输出最优路线。
项目经历了四次重构,形成了最终版。蓝色的那个是最终版,重构主要是想法的改变和方法的改变。
第一个是数据库俩个表:站点表存贮所有站点和他们所在的线路,但是转站点的所在路线设为-1(特别区分)
有六种情况:1.无转站点,俩点在一条线路路 2.无转站点,俩点不在条线路路 3.一个转站点,俩点在一条路上 4.一个转站点,俩点不在一条路上 5.俩个转站点,俩点在一条路上 6.俩个转站点,俩点不在一条路上。
然后如果最优的话,肯定是转站最少啊。写java代码,后来发现如果有一个环路线,有时候多转战要更近。
放弃!
第二个是学习dijkstra算法,数据库里面的数据也是俩个表,一个站点表,一个站点关系表。使用邻接链表和多次调用sql语句。电脑难屏死机,气的我牙根疼。
放弃,但是这个方案是可行的,但是中途放弃了。
重点:因为多次调用sql语句电脑才死机的,而不是邻接链表存贮,应该一次把数据全取出来用java代码处理。
放弃!
第三个是回到第一个的方法,想要多建表来实现那种功能,但是情况却多了起来,好多个表之间的对比求取,太麻烦了。写累了,决定放弃。
放弃!
第四个是我还是想用dijkstra算法,但是怎样不死机呢?数据库同第二个。用矩阵(二维整数数组)来代替就简单了白,-1是到不了,自己到自己是0,因为不知道距离
所以剩下的全是1,以后知道距离了,就可以把距离代替1,这样求出来的就是真正的时间最优路线,而不是理想化的了。(理想化:站点与站点之间距离一样)
成功!
做web的良好的习惯,使用的是mysql数据库,DButil层(连接数据库和关闭连接)+bean层+dao层(取数据库数据)+service层(服务层)
站点表:表内140个站点
站点关系表:151个关系
运行截图:
遇到的问题:
重点1:因为多次调用sql语句电脑才死机的,而不是邻接链表存贮,应该一次把数据全取出来用java代码处理。
for(sql)不知道为什么就是会卡死,网上说这样会占用大量的cpu和内存,我觉得是mysql的斯必得跟不上JVM虚拟机。
重点2:学习dijkstra算法,我挺笨的,学习了挺久的。
重点3:mysql的数据里面是存贮空格的,因为做完以后得排查数据库错误,有一个站点一直查不到,因为它是站点名+一个空格。。。
DButil包内:
1 package DButil; 2 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.PreparedStatement; 6 import java.sql.ResultSet; 7 import java.sql.SQLException; 8 import java.sql.Statement; 9 10 /** 11 * 数据库的工具类 12 * 13 * @author 达达超可爱 14 * 15 */ 16 public final class DButil { 17 18 19 /** 20 * 数据库的连接函数 21 * 可修改的 22 * 23 * @return 数据库的连接 24 */ 25 public Connection getConn() 26 { 27 Connection connection =null; 28 // student 为数据库名称 ? 后面加的是条件 29 String db_url="jdbc:mysql://localhost:3306/newsubway?serverTimezone=UTC&useCursorFetch=true&defaultFetchSize=300"; 30 try { 31 Class.forName("com.mysql.cj.jdbc.Driver"); 32 connection = DriverManager.getConnection(db_url, "root", "123456"); 33 // System.out.println("Success connect MySql server!"); 34 35 } catch (Exception e) { 36 37 } 38 39 return connection; 40 } 41 42 public void close(Connection con) 43 { 44 if(con!=null) 45 { 46 try { 47 con.close(); 48 } catch (SQLException e) { 49 e.printStackTrace(); 50 } 51 } 52 } 53 54 public void close(Statement state, Connection conn) { 55 if (state != null) { 56 try { 57 state.close(); 58 } catch (SQLException e) { 59 e.printStackTrace(); 60 } 61 } 62 if (conn != null) { 63 try { 64 conn.close(); 65 } catch (SQLException e) { 66 e.printStackTrace(); 67 } 68 } 69 } 70 public void close( PreparedStatement state, Connection conn) { 71 if (state != null) { 72 try { 73 state.close(); 74 } catch (SQLException e) { 75 e.printStackTrace(); 76 } 77 } 78 if (conn != null) { 79 try { 80 conn.close(); 81 } catch (SQLException e) { 82 e.printStackTrace(); 83 } 84 } 85 } 86 public void close(ResultSet rs, PreparedStatement state, Connection conn) { 87 if (rs != null) { 88 try { 89 rs.close(); 90 } catch (SQLException e) { 91 e.printStackTrace(); 92 } 93 } 94 if (state != null) { 95 try { 96 state.close(); 97 } catch (SQLException e) { 98 e.printStackTrace(); 99 } 100 } 101 if (conn != null) { 102 try { 103 conn.close(); 104 } catch (SQLException e) { 105 e.printStackTrace(); 106 } 107 } 108 } 109 public void close(ResultSet rs, Statement state, Connection conn) { 110 if (rs != null) { 111 try { 112 rs.close(); 113 } catch (SQLException e) { 114 e.printStackTrace(); 115 } 116 } 117 if (state != null) { 118 try { 119 state.close(); 120 } catch (SQLException e) { 121 e.printStackTrace(); 122 } 123 } 124 if (conn != null) { 125 try { 126 conn.close(); 127 } catch (SQLException e) { 128 e.printStackTrace(); 129 } 130 } 131 } 132 }
bean包内:
1 package bean; 2 3 public class Daobean { 4 5 6 String name; 7 8 public String getName() { 9 return name; 10 } 11 12 public void setName(String name) { 13 this.name = name; 14 } 15 16 17 }
1 package bean; 2 3 public class PointBean { 4 5 int line; 6 String name; 7 int number; 8 public int getLine() { 9 return line; 10 } 11 public void setLine(int line) { 12 this.line = line; 13 } 14 public String getName() { 15 return name; 16 } 17 public void setName(String name) { 18 this.name = name; 19 } 20 public int getNumber() { 21 return number; 22 } 23 public void setNumber(int number) { 24 this.number = number; 25 } 26 27 }
1 package bean; 2 //站点与站点之间的联系关系 3 public class Changebean { 4 5 String name1; 6 String name2; 7 public String getName1() { 8 return name1; 9 } 10 public void setName1(String name1) { 11 this.name1 = name1; 12 } 13 public String getName2() { 14 return name2; 15 } 16 public void setName2(String name2) { 17 this.name2 = name2; 18 } 19 20 }
dao包内:
1 package dao; 2 3 import java.sql.Connection; 4 import java.sql.ResultSet; 5 import java.sql.Statement; 6 import java.util.ArrayList; 7 import java.util.List; 8 9 import DButil.DButil; 10 import bean.Changebean; 11 import bean.Daobean; 12 import bean.PointBean; 13 14 15 16 public class Dao { 17 //返回所有点的名称为一个数组 18 public List<Daobean> selectDaoList() 19 { 20 List<Daobean> l=new ArrayList<Daobean>(); 21 Daobean b=null; 22 23 try 24 { 25 DButil DB=new DButil(); 26 Connection con = DB.getConn(); 27 Statement stm = con.createStatement(); 28 ResultSet rs = stm.executeQuery("select * from point"); 29 while(rs.next()) 30 { 31 b=new Daobean(); 32 b.setName(rs.getString("name")); 33 l.add(b); 34 } 35 DB.close(rs, stm, con); 36 } catch (Exception e) 37 { 38 e.printStackTrace(); 39 40 } 41 return l; 42 } 43 //返回所有点的关系为一个数组 44 //每个点与点 之间的长度此时未知无法使用 45 public List<Changebean> selectChangeList() 46 { 47 List<Changebean> l=new ArrayList<Changebean>(); 48 Changebean b=null; 49 50 try 51 { 52 DButil DB=new DButil(); 53 Connection con = DB.getConn(); 54 Statement stm = con.createStatement(); 55 ResultSet rs = stm.executeQuery("select point1,point2,length from pointlian"); 56 while(rs.next()) 57 { 58 b=new Changebean(); 59 b.setName1(rs.getString("point1")); 60 b.setName2(rs.getString("point2")); 61 l.add(b); 62 } 63 DB.close(rs, stm, con); 64 } catch (Exception e) 65 { 66 e.printStackTrace(); 67 68 } 69 return l; 70 } 71 72 public List<PointBean> selectPointList() 73 { 74 List<PointBean> l=new ArrayList<PointBean>(); 75 PointBean b=null; 76 77 try 78 { 79 DButil DB=new DButil(); 80 Connection con = DB.getConn(); 81 Statement stm = con.createStatement(); 82 ResultSet rs = stm.executeQuery("select name,number from point"); 83 while(rs.next()) 84 { 85 b=new PointBean(); 86 b.setName(rs.getString("name")); 87 // b.setLine(rs.getInt("line")); 88 b.setNumber(rs.getInt("number")); 89 l.add(b); 90 } 91 DB.close(rs, stm, con); 92 } catch (Exception e) 93 { 94 e.printStackTrace(); 95 96 } 97 return l; 98 } 99 100 }
Servise包内:
1 package service; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import bean.Changebean; 7 import bean.Daobean; 8 import bean.PointBean; 9 import dao.Dao; 10 11 public class TrainService { 12 //主要调用函数 调用这个就行 13 public String trainText(String start,String end) 14 { 15 16 Dao dao = new Dao();// 使用Dao层 17 List<Daobean> l = new ArrayList<Daobean>(); 18 List<Changebean> n = new ArrayList<Changebean>(); 19 l = dao.selectDaoList(); 20 n = dao.selectChangeList(); 21 Integer startnumber=null; 22 Integer endnumber=null; 23 for(int i=0;i<l.size();i++) 24 { 25 if(start.equals(l.get(i).getName())) 26 { 27 startnumber=i; 28 } 29 if(end.equals(l.get(i).getName())) 30 { 31 endnumber=i; 32 } 33 } 34 // l为所有点的名称 n为所有点之间的关系 35 // 构建邻接矩阵 36 // -1为不相邻,1是相邻,0是自己和自己 37 38 // 建立战点与战点之间的图形 39 // 初始化矩阵,全为-1 40 int[][] m = new int[l.size()][l.size()]; 41 42 for (int i = 0; i < l.size(); i++) 43 { 44 45 for (int j = 0; j < l.size(); j++) 46 { 47 m[i][j] = -1; 48 } 49 } 50 // 根据关系把矩阵中为1的找出来 51 for (int i = 0; i < l.size(); i++) 52 { 53 Daobean b1 = new Daobean(); 54 b1 = l.get(i); 55 for (int j = 0; j < l.size(); j++) 56 { 57 Daobean b2 = new Daobean(); 58 b2 = l.get(j); 59 m[i][j] = returnint(b1.getName(), b2.getName(), n, m[i][j]); 60 } 61 62 } 63 // 自己与自己为0 64 for (int i = 0; i < l.size(); i++) 65 { 66 m[i][i] = 0; 67 } 68 // 因为地铁双向所以为无向图,因此需要它的转置矩阵后与原矩阵相加的规律把它对角线的全为1 69 for (int i = 0; i < l.size(); i++) 70 { 71 for (int j = 0; j < l.size(); j++) 72 { 73 if (m[i][j] == 1) { 74 m[j][i] = 1; 75 } 76 } 77 } 78 // 需要修改的地方 79 /// 80 //// 81 ///// 82 l.clear(); 83 n.clear(); 84 85 String mm=null; 86 if(startnumber==null||endnumber==null) 87 { 88 mm="请输入正确的地点"; 89 } 90 else 91 { 92 String b = dijkstra(m, startnumber, endnumber); 93 // 去除空格 94 String[] re = b.split(" ");// 用split()函数直接分割 95 int rep[] = new int[re.length]; 96 for (int i = 0; i < re.length; i++) 97 { 98 rep[i] = Integer.parseInt(re[i]); 99 } 100 //for (int i = 0; i < re.length; i++) 101 { 102 //System.out.print(" " + rep[i]); 103 } 104 //System.out.println(); 105 List<PointBean> lll = new ArrayList<PointBean>(); 106 lll = dao.selectPointList(); 107 {/* 108 * for(int i=0;i<lll.size();i++) { 109 * System.out.println(i+" "+lll.get(i).getNumber()); } 110 */ 111 } 112 mm = returnWay(rep, lll); 113 } 114 mm = mm.substring(0,mm.length() - 2); 115 return mm; 116 } 117 118 public String returnWay(int[] n, List<PointBean> list) 119 { 120 String a = ""; 121 int line = 0; 122 for (int j = 0; j < list.size(); j++) 123 { 124 if ((n[0] + 1) == list.get(j).getNumber()) 125 { 126 // a=a+""+list.get(j).getLine()+"号线:"+list.get(j).getName()+"->"; 127 a = a + "" + list.get(j).getName() + "->"; 128 line = list.get(j).getLine(); 129 } 130 } 131 for (int i = 1; i < n.length; i++) 132 { 133 for (int j = 0; j < list.size(); j++) 134 135 { 136 if ((n[i] + 1) == list.get(j).getNumber()) 137 { 138 if (line != list.get(j).getLine()) 139 { 140 line = list.get(j).getLine(); 141 a = a + "" + list.get(j).getLine() + "号线:"; 142 } 143 a = a + "" + list.get(j).getName() + "->"; 144 } 145 } 146 147 } 148 149 return a; 150 } 151 152 // 获取最短路径 返回的是一个String,需要处理 153 public static String getRoute(int[][] WW, int[] indexs, int end, String a, int b) 154 { 155 String[] routeArray = new String[indexs.length]; 156 String dada = b + ""; 157 if (dada.length() == 1) 158 { 159 dada = " " + b; 160 } 161 if (dada.length() == 2) 162 { 163 dada = " " + b; 164 } 165 166 for (int i = 0; i < routeArray.length; i++) 167 { 168 routeArray[i] = ""; 169 } 170 171 routeArray[indexs[0]] = indexs[0] + ""; 172 for (int i = 1; i < indexs.length; i++) 173 { 174 // 看该点与前面所有点的连接线中的最短路径,然后得到该最短路径到底是连接了哪个点,进而此点的route就是找出那点的route+此点 175 int[] thePointDis = WW[indexs[i]]; 176 int prePoint = 0; 177 178 int tmp = 9999; 179 for (int j = 0; j < thePointDis.length; j++) 180 { 181 boolean chooseFlag = false; 182 for (int m = 0; m < i; m++) 183 { 184 if (j == indexs[m]) 185 { 186 chooseFlag = true; 187 } 188 } 189 if (chooseFlag == false) 190 { 191 continue; 192 } 193 if (thePointDis[j] < tmp && thePointDis[j] > 0) 194 { 195 prePoint = j; 196 tmp = thePointDis[j]; 197 } 198 } 199 routeArray[indexs[i]] = routeArray[prePoint] + " " + indexs[i]; 200 } 201 for (int i = 0; i < routeArray.length; i++) 202 { 203 204 if (routeArray[i].length() > 3 205 && routeArray[i].substring(routeArray[i].length() - 3, routeArray[i].length()).equals(dada)) 206 { 207 a = routeArray[i]; 208 } 209 } 210 return a; 211 } 212 213 public static String dijkstra(int[][] W1, int start, int end) 214 { 215 String b = ""; 216 boolean[] isLabel = new boolean[W1[0].length];// 是否标号 217 int[] indexs = new int[W1[0].length];// 所有标号的点的下标集合,以标号的先后顺序进行存储,实际上是一个以数组表示的栈 218 int i_count = -1;// 栈的顶点 219 int[] distance = W1[start].clone();// v0到各点的最短距离的初始值 220 int index = start;// 从初始点开始 221 int presentShortest = 0;// 当前临时最短距离 222 223 indexs[++i_count] = index;// 把已经标号的下标存入下标集中 224 isLabel[index] = true; 225 226 while (i_count < W1[0].length) 227 { 228 // 第一步:得到与原点最近的某个点 229 int min = Integer.MAX_VALUE; 230 for (int i = 0; i < distance.length; i++) 231 { 232 if (!isLabel[i] && distance[i] != -1 && i != index) 233 { 234 // 如果到这个点有边,并且没有被标号 235 if (distance[i] < min) 236 { 237 min = distance[i]; 238 index = i;// 把下标改为当前下标 239 } 240 } 241 } 242 i_count = i_count + 1; 243 if (i_count == W1[0].length) 244 { 245 break; 246 } 247 isLabel[index] = true;// 对点进行标号 248 indexs[i_count] = index;// 把已经标号的下标存入下标集中 249 250 if (W1[indexs[i_count - 1]][index] == -1 251 || presentShortest + W1[indexs[i_count - 1]][index] > distance[index]) 252 { 253 // 如果两个点没有直接相连,或者两个点的路径大于最短路径 254 presentShortest = distance[index]; 255 } else { 256 presentShortest += W1[indexs[i_count - 1]][index]; 257 } 258 259 // 第二步:加入vi后,重新计算distance中的距离 260 for (int i = 0; i < distance.length; i++) 261 { 262 263 // 如果vi到那个点有边,则v0到后面点的距离加 264 if (distance[i] == -1 && W1[index][i] != -1) 265 {// 如果以前不可达,则现在可达了 266 distance[i] = presentShortest + W1[index][i]; 267 } else if (W1[index][i] != -1 && presentShortest + W1[index][i] < distance[i]) 268 { 269 // 如果以前可达,但现在的路径比以前更短,则更换成更短的路径 270 distance[i] = presentShortest + W1[index][i]; 271 } 272 273 } 274 275 } 276 b = getRoute(W1, indexs, end, b, end); 277 return b; 278 279 } 280 281 // 将矩阵对应位置判断是否为1 282 public static int returnint(String b1, String b2, List<Changebean> n, int i) 283 { 284 for (int j = 0; j < n.size(); j++) 285 { 286 if (b1.equals(n.get(j).getName1()) && b2.equals(n.get(j).getName2())) 287 { 288 i = 1; 289 } 290 } 291 return i; 292 } 293 }