地铁线路项目学习记录

地铁线路项目学习记录

github地址:https://github.com/zky320/Subway


使用的命令行语句

1. 获取对应的自定义地铁文件(命名为 subway.txt)

java -cp .:* subway -map subway.txt

2. 获取指定铁路线路的所有站点名称,并存入指定文件

java -cp .:* subway -a 1号线 -map subway.txt -o station.txt

输出文件格式:

1号线:
······
洪湖里
西站(可转6号线)
西北角
······

3. 获取起点站和终点站的最短路径,并存入指定文件

java -cp .:* subway -b 洪湖里 复兴路 -map subway.txt -o routine.txt

输出文件格式:

3        
洪湖里
西站
6号线
复兴路

Tips:java文件中需要调用jar包,命令行中的格式为 java -cp .:A.jar B ,而 java -cp .:* subway 可以调用当前文件夹中的所有jar包。


测试用例(最短路径):例子

1. 在同一条线路(的头)上,不经过任何转站点:刘园,洪湖里

2. 在同一条线路(的尾)上,不经过任何转站点:市民广场,东海路

3. 在同一条线路的中间,不经过任何转站点:北竹林,新开河

4. 起点和终点都是转站点(在同一条线上):西站,下瓦房

5. 起点和终点都是转站点(不在同一条线上):西站,张兴庄

6. 起点为转站点,终点非转站点:西站,一号桥

7. 起点非转站点,终点为转站点(中途包括逆向):李楼,直沽

8. 起点和终点都非转站点:天泰路,和平路

9. 5号线和6号线特殊交叠,起点和终点都在5号线和6号线上:肿瘤医院,文化中心

10. 5号线和6号线特殊交叠,起点和终点都不在5号线和6号线上,但途经(不发生转站):西南楼,体育中心

11. 5号线和6号线特殊交叠,起点和终点都不在5号线和6号线上,但途经(发生转站):西南楼,水上公园东路


部分错误提示

1. 命令错误

2. 自定义地铁文件错误

3. 无指定地铁线路

4. 起点终点相同

5. 琐碎的输入错误或命令错误


代码实现

使用编程语言:java

1. 读取对应的自定义文件:

自定义文件格式:

6    ->地铁线路数
15    ->转站数
1 23    ->地铁线路名  该地铁线路含有多少站点
刘园 0    ->站点名  转站(不转站为0,转站则为转站的地铁线路名)
西横堤 0
果酒厂 0
本溪路 0
勤俭道 0
洪湖里 0
西站 6
······

【一开始为三元组(地铁线路名,地铁站名,转站线路号),开始写代码的时候发现这样的格式存储起来不太方便,改成了二元组(地铁站名,转站线路号)】

存储数据方式:Json对象+Json数组 

{
"1号线": [
{ "siteName":"刘园" , "transfer":"0" },
{ "siteName":"西横堤" , "transfer":"0" },
{ "siteName":"果酒厂" , "transfer":"0" },
  ........
]
}
{
"2号线": [
{ "siteName":"曹庄" , "transfer":"0" },
{ "siteName":"卞兴" , "transfer":"0" },
{ "siteName":"芥园西道" , "transfer":"0" },
  ........
]
}
{
  ........
}

读取文件并存储数据代码如下:

 1 public static void readtxt(String txt){
 2         int mark=0;
 3         int nn=0;   //用于添加subwayN,用于后期读取JsonArray来创建图
 4         int subwaynum=0;
 5         int subwaysum=0;
 6         JSONArray jArr = null;
 7         String txtname = txt;
 8 
 9         try (FileReader reader = new FileReader(txtname);
10              BufferedReader br = new BufferedReader(reader) // 建立一个对象,它把文件内容转成计算机能读懂的语言
11         ) {
12             String line;
13             while ((line = br.readLine()) != null) {
14                 String[] str=line.split(" ");
15                 Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
16                 if(str.length==1&&mark==0){  //说明是第一行,记录地铁线路有几条
17                     num=Integer.valueOf(str[0]);
18                     subwayN=new String[num];    //将几号线的名字都存起来
19                     mark++;
20 //                    System.out.println(num);
21                 }
22                 else if(str.length==1&&mark!=0){
23                     trannum=Integer.valueOf(str[0]);
24 //                    System.out.println(trannum);
25                 }
26                 else if(pattern.matcher(str[0]).matches()&&pattern.matcher(str[1]).matches()){  //说明是描述线路的两个数字
27                     subwaynum=Integer.valueOf(str[0]);
28                     subwaysum=Integer.valueOf(str[1]);
29                     subwayN[nn++]=str[0]+"号线";
30                     jArr = new JSONArray();
31 //                    System.out.println(subwaynum+" "+subwaysum);
32                 }
33                 else {  //正常站点名称
34                     JSONObject jobj = new JSONObject();
35                     try {
36                         jobj.put("siteName", str[0]);
37                         jobj.put("transfer", str[1]);
38 
39                     } catch (JSONException e) {
40                         e.printStackTrace();
41                     }
42                     jArr.add(jobj);
43                     flag++;
44                     if(flag==subwaysum){
45                         all.put(subwaynum+"号线",jArr);
46                         flag=0;
47                     }
48                 }
49             }
50             if(flag==num){
51                 all.put(subwaynum+"号线",jArr);
52             }
53 //            System.out.println(all);
54 //            System.out.println(all.getJSONArray("1号线").getJSONObject(0).getString("siteName"));
55         } catch (IOException e) {
56             e.printStackTrace();
57         }
58     }

2. 输出地铁线路所有地铁站名称:

  将Json对应对象中的数组读出,并全部输出,代码如下:

 1 public static void writeallstation(String subwaynum,String txt) {
 2         JSONArray Jarray = all.getJSONArray(subwaynum);
 3         try {
 4             File writeName = new File(txt); // 相对路径,如果没有则要建立一个新的output.txt文件
 5             writeName.createNewFile(); // 创建新文件,有同名的文件的话直接覆盖
 6             try (FileWriter writer = new FileWriter(writeName);
 7                  BufferedWriter out = new BufferedWriter(writer)
 8             ) {
 9                 out.write(subwaynum+":\n");
10                 for(int i=0;i<Jarray.size();i++){
11 //                    System.out.print(Jarray.getJSONObject(i).getString("siteName"));
12                     out.write(Jarray.getJSONObject(i).getString("siteName"));
13                     String num=Jarray.getJSONObject(i).getString("transfer");
14                     if(!num.equals("0")){
15                         if(num.length()==1){
16 //                            System.out.println("(可转"+num+"号线)");
17                             out.write("(可转"+num+"号线)\n");
18                         }
19                         else{
20 //                            System.out.println("(可转"+num.charAt(0)+"号线和"+num.charAt(1)+"号线)");
21                             out.write("(可转"+num.charAt(0)+"号线和"+num.charAt(1)+"号线)\n");
22                         }
23                     }
24                     else{
25 //                        System.out.println();
26                         out.write("\n");
27                     }
28                 }
29                 out.flush(); // 把缓存区内容压入文件
30             }
31         } catch (IOException e) {
32             e.printStackTrace();
33         }
34     }

3.  输出最短路径:

  将转站节点(一共15个)连接成图,之后将起点站和终点站加入图中,中途出现各种特殊情况,需要将加入点连入图中后删除原本已有的另一条边。在建立图的过程中,一一记录节点在图中的序号,连成完整的无向图后使用 Dijstra 算法取其最短路径。在输出起点到终点的地铁路线时,需要输出转站情况,所以再这之前,将各条地铁线路上包含的图中节点(在图中的序号)进行了记录,当判断改站为转站点时,需检查改点与下一个节点同时出现在哪一条地铁线路中,若改号线路与当前不是同一条,则输出转站情况。

  建图过程中做了数据记录以参照

【 过程中本来想换成将所有站点(一共141个)连成图,之后直接使用 Dijstra 算法取其最短路径。但转念一想觉得原理相同,最终还是选择了原本的方法,写到后期有点后悔,因为各种繁琐 

 最短路径 Dijstra 算法代码如下:

 1 public static String dijkstra(int start, int end) {
 2         // 初始化,第一个顶点求出
 3         int n=record.size();
 4         final int M = Integer.MAX_VALUE;
 5         int[] shortest = new int[n];  //存放从start到其他节点的最短路径
 6         boolean[] visited = new boolean[n]; //标记当前该顶点的最短路径是否已经求出,true表示已经求出
 7         shortest[start] = 0;
 8         visited[start] = true;
 9 
10         //存放从start到其他各节点的最短路径
11         String[] path = new String[n];
12         for(int i = 0; i < n; i++){
13             path[i] = new String(start + "->" + i);
14         }
15         for(int count = 0; count != n-1; count ++){
16             //选出一个距离初始顶点最近的为标记顶点
17             int k = M;
18             int min = M;
19             for(int i =0; i< n ; i++){//遍历每一个顶点
20                 if( !visited[i] && graph[start][i] != M){ //如果该顶点未被遍历过且与start相连
21                     if(min == -1 || min > graph[start][i]){ //找到与start最近的点
22                         min = graph[start][i];
23                         k = i;
24                     }
25                 }
26             }
27             //正确的图生成的矩阵不可能出现K== M的情况
28             if(k == M) {
29                 System.out.println("the input map matrix is wrong!");
30                 return null;
31             }
32             shortest[k] = min;
33             visited[k] = true;
34             //以k为中心点,更新start到未访问点的距离
35             for (int i = 0; i < n; i++) {
36                 if (!visited[i] && graph[k][i] != M) {
37                     int callen = min + graph[k][i];
38                     if (graph[start][i] == M || graph[start][i] > callen) {
39                         graph[start][i] = callen;
40                         path[i] = path[k] + "->" + i;
41                     }
42                 }
43             }
44         }
45 
46 //        System.out.println("从"+start+"出发到"+end+"的最短路径为:"+path[end]);
47 
48         return path[end];
49     }

总结

  总体来说,顺利完成要求,但方法很繁琐,主要还是开始时考虑得不到位,写到中途又不愿意放弃前期花进去的时间。就当是一次教训,以后还是以此为戒。

猜你喜欢

转载自www.cnblogs.com/zky0320/p/11637614.html