2019软件工程——地铁个人项目总结

时间:2019-10-15
本文章向大家介绍2019软件工程——地铁个人项目总结,主要包括2019软件工程——地铁个人项目总结使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

GitHub

CHNTuring/metro

项目要求

实现类似百度地图等应用的公共交通换乘查询功能,要求为北京地铁换乘

开发环境

Windows10操作系统,java version "1.8.0_221",开发工具eclipse

项目效果预览

 Java类表

说明
metroUtil 项目入口
ReaderTxt 将含有站点和线路信息的.txt文件读取并存入数据结构
Station 地铁站类
Subway Java UI地铁系统,将数据结构转化为图
Dijkstra 迪杰斯特拉算法寻找合理的换乘方案

 .txt文件格式

从左至右依次为线路编号,站点名称,所属线路,开通状态,是否换乘站。文件中某站点上下相邻站点若属于同一地铁线,则默认现实中互为相邻站点。

 程序流程

算法思想

  地铁线路换乘查询其本质上为图的最短路径问题,在本项目中可以理解为寻找无向图起始节点与目的节点之间的最短路径,并记录路径输出在UI中。

  1:有效数据读取,即读取开通的站点及其所属线路,存储为类ReaderTxt 的静态属性Map<String, List<Station>> map。

void readFileContent(String fileName)  
        reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
            String tempStr = null;
            int staId = 0;//站点编号,唯一
            int time = 0;
            while ((tempStr = reader.readLine()) != null) {// 判断是否读到文件末尾
                if (time == 0) {// 如果读取的是第一条数据则初始化站点列表对象
                    time++;
                    line_stations = new LinkedList<>();
                }
                String[] message = tempStr.split("\\s+");// 分割站点信息
                lines.add(message[2]);// 读地铁线路
                if (message[3].equals("1")) {// 读取开通的地铁站
                    // 读取同一条线路的站点,读完则更新map并重新创建新线路的站点列表
                    if (!allStations.isEmpty()
                            && !((Station) ((LinkedList) allStations).getLast()).getLine().equals(message[2])) {
                        map.put(((Station) ((LinkedList) allStations).getLast()).getLine(), line_stations);
                        line_stations = new LinkedList<>();
                    }
                    Station station = new Station(staId++, message[1], message[2], message[4].equals("1"));
                    allStations.add(station);
                    line_stations.add(station);
                }
            }

            reader.close();

  2:数据预处理,考虑北京地铁线路存在环线的特殊情况,即起始站点和终点站为同一站点,则需要将原来存储在map中的数据信息去重,同时更新站点编号(唯一),存储所有站点信息到List<Station> allStations ,初始化int型矩阵graph用于存储站点间的连通情况

void initialize() 

具体实现见Github

  3:换乘查询,其核心算法为迪杰斯特拉算法,由Dijkstra类实现

Dijkstra类属性

/* 属性 */

private Queue visited = null;// 已访问站点

int[] distance = null;;// 路径长度

private Map<String, List<Station>> line_stations = null;

static String nowLine = null;// 当前地铁线

static String[] nextLine = null;// 当前节点的下一换乘地铁线

static HashMap path = null;// 路径

static List<Station> list = null;

初始化路径长度数组distance

// 路径HashMap path;
path = new HashMap();
for (int i = 0; i < list.size(); i++)
    path.put(i, "");

// 初始化路径长度数组distance
for (int i = 0; i < list.size(); i++) {
    path.put(i, path.get(i) + "" + list.get(v).getStaName());
    if (i == v)
       distance[i] = 0;
    // 连通站点
    else if (weight[v][i] != -1) {
       distance[i] = weight[v][i];
       // 获取当前站点所属的地铁线
       nowLine = list.get(v).getLine();
       StringBuffer sbf = new StringBuffer();
       for (Station s : line_stations.get(nowLine)) {
           sbf.append(s.getStaName());
       }
       // 起点站和下一站点是否属于同一地铁线
       if (sbf.indexOf(list.get(i).getStaName()) != -1) {
          path.put(i, path.get(i) + "\n\t-->" + list.get(i).getStaName());
          nextLine[i] = nowLine;
       } else {
          path.put(i, path.get(i) + "\n-->换乘" + list.get(i).getLine() + "\n\t-->" + list.get(i).getStaName());
          nextLine[i] = list.get(i).getLine();
       }
    }
    // 不连通
    else
        distance[i] = Integer.MAX_VALUE;
}
visited.add(v);

迭代寻找最优路径

//迭代寻找最优线路
while (visited.size() < list.size()) {
    int k = getIndex(visited, distance);// 获取未访问点中距离源点最近的点
    visited.add(k);
    if (k != -1) {

        for (int j = 0; j < list.size(); j++) {
            if (weight[k][j] != -1)// 判断k点能够直接到达的点
            {
                // 通过遍历各点,比较是否有比当前更短的路径,有的话,则更新distance,并更新path。
                if (distance[j] > distance[k] + weight[k][j]) {
                    distance[j] = distance[k] + weight[k][j];

                    nowLine = nextLine[k];
                    StringBuffer sbf = new StringBuffer();
                    for (Station s : line_stations.get(nowLine)) {
                        sbf.append(s.getStaName());
                    }
                    //判断到下一站点是否需要换乘
                    if (sbf.indexOf(list.get(j).getStaName()) != -1) {
                        path.put(j, path.get(k) + "\n\t-->" + list.get(j).getStaName());
                        nextLine[j] = nowLine;
                    } else {
                        StringBuffer tmpSbf = new StringBuffer();

                        for (String str : line_stations.keySet()) {
                            tmpSbf = new StringBuffer();
                            for (Station s : line_stations.get(str)) {
                                tmpSbf.append(s.getStaName());
                            }
                            if (tmpSbf.indexOf(list.get(j).getStaName()) != -1
                                    && tmpSbf.indexOf(list.get(k).getStaName()) != -1) {
                                path.put(j,
                                        path.get(k) + "\n-->换乘" + str + "\n\t-->" + list.get(j).getStaName());
                                nextLine[j] = str;
                            }
                        }
                    }
                }
            }
        }
    }
}

个人总结

  地铁项目是软件工程课的个人项目,一开始以为可以很容易实现,结果花了不少时间来构思合理的数据结果来存储线路和站点信息,完成所有功能模块后发现其实代码和流程可以更进一步优化,终版代码的复杂度其实是受到了一开始的.txt数据文件的束缚,读取.txt文件需要处理地铁线和站点的之间的站点和所属线路、相邻站点之间的约束关系,代码量和复杂度就相应的增大了不少,通过这次实战,涨了不少经验值,开发初期如果综合考虑.txt数据的存储形式或者数据处理方式,后期可以节省很大的时间精力和开销来编写可读性和可优化性更好的代码。

原文地址:https://www.cnblogs.com/hjw31701010/p/11675158.html