31701056

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

软件工程Test1项目总结

1.主要功能

在正确输入所需信息的前提下,本程序提供某地区地铁路线的线路详情与最短线路查询功能

2.实现语言

JAVA

3.实现算法

主要算法为Dijkstra算法

4.类职责划分(将相关类的功能进行描述)

本程序大致划分为3部分:UI类,封装类,控制类(数据生成类)

1).UI类

提供用户界面:包括欢迎界面(功能选择),线路查询界面,线路详情界面,提示窗口等

线路查询界面下,用户输入起始站与终点站,开始查询后,若系统没有检测到起始站或终点站,则弹出提示框;查询完成后,在结果窗口输出所求线路

线路详情界面下,用户选择某一条线路,查询完成后,在结果窗口输出该线路下的所有站点

2).封装类

包括地铁站点类(节点),地铁线路类(边),权重图构造类等

原始信息会经过数据构造后存放到相应的封装类

3).控制类

包含处理算法,对权重图进行初始化与计算

计算任意两个站点间的最短路径并按一定格式输出

5.核心代码(将所有类的代码标注并提交)

控制部分:

 DataBuilder类

public class DataBuilder /*throws IOException*/{

    public static Set<List<Station>> lineSet = new HashSet<List<Station>>();//所有线集合
    public static List<Line> AllLine = new ArrayList<Line>();//所有线集合
    public static Map<String, List<Station>> map = new HashMap<String, List<Station>>();
    public static List<Station> mapOfStation = new ArrayList<Station>();//存放所有站点
    public static int totalStaion = 0;//总的站点数量

    public static void setStations(List<Station> linemodel, String str) {
        String line=str;
        String[] line1Arr = line.split(" ");
        int flag=0;
        String linename = null;
        Line newline=new Line();
        for(String s : line1Arr){
            if(flag==0){
                linename=s;
                newline.setName(linename);
            }
            else{
                Station station=new Station(s);
                for(List<Station> lineP : DataBuilder.lineSet){
                    if(lineP.contains(station)){
                        DataBuilder.totalStaion -=1;//在其他线路出现过就减1站,不然会重复计算
                        break;
                    }
                }
                mapOfStation.add(station);
                station.setLinename(linename);
                linemodel.add(station);
            }
            flag=1;
        }
        for(int i =0;i<linemodel.size();i++){
            if(i<linemodel.size()-1){
                linemodel.get(i).next = linemodel.get(i+1);
                linemodel.get(i+1).prev = linemodel.get(i);
            }
        }
        newline.setStations(linemodel);
        AllLine.add(newline);
        map.put(linename,linemodel);
    }
    static {
        for(int i=0;i<Subway.lines.size();i++){
            List<Station> line = new ArrayList<Station>();
            setStations(line,Subway.lines.get(i));
            totalStaion += line.size();
            lineSet.add(line);
        }
    }
}

Subway类

public class Subway {
    public static List<String> lines = new ArrayList<>();//存放所有的线路
    public static List<String> route = new ArrayList<>();
    private List<Station> outList = new ArrayList<Station>();//记录已经分析过的站点
    
    public void calculate(Station s1, Station s2){//计算从s1站到s2站的最短经过路径
        String line="初始线";
        if(outList.size() == DataBuilder.totalStaion){
            route.add("找到目标站点:"+s2.getName()+",共经过"+(s1.getAllPassedStations(s2).size()-1)+"站\n");
            int flag=0;
            for(Station station : s1.getAllPassedStations(s2)){
                if(station.getLinename()==null){//出发站
                    route.add(station.getName()+"->");
                }
                else if(station.getName().equals(s2.getName())){//最后1站
                    if(!station.getLinename().equals(line)){
                        route.add("换乘 "+station.getLinename()+"->"+"到达 "+station.getName());
                    }
                    else {
                        route.add("到达 "+station.getName());
                    }
                }
                else if(!station.getLinename().equals(line)&&flag==1){//换乘后1站
                    line=station.getLinename();
                    route.add("换乘"+station.getLinename()+"->"+station.getName()+"->");
                }
                else if(!station.getLinename().equals(line)&&flag==0){//第2站
                    line=station.getLinename();
                    route.add("乘坐"+station.getLinename()+"->"+station.getName()+"->");
                    flag=1;
                }
                else{//其余站
                    line=station.getLinename();
                    route.add(station.getName()+"->");
                }
            }
            return;
        }
        if(!outList.contains(s1))
            outList.add(s1);
        //如果起点站的OrderSetMap为空,则第一次用起点站的前后站点初始化之
        if(s1.getOrderSetMap().isEmpty()){
            List<Station> Linkedstations = getAllLinkedStations(s1);
            for(Station s : Linkedstations){
                s1.getAllPassedStations(s).add(s);
            }
        }
        Station parent = getShortestPath(s1);//获取距离起点站s1最近的一个站(有多个的话,随意取一个)
        if(parent == s2){
            System.out.println("找到目标站点:"+s2+",共经过"+(s1.getAllPassedStations(s2).size()-1)+"站");
            for(Station station : s1.getAllPassedStations(s2)){
                System.out.print(station.getName()+"->");
            }
            return;
        }
        for(Station child : getAllLinkedStations(parent)){
            if(outList.contains(child)){
                continue;
            }
            int shortestPath = (s1.getAllPassedStations(parent).size()-1) + 1;//前面这个1表示计算路径需要去除自身站点,后面这个1表示增加了1站距离
            if(s1.getAllPassedStations(child).contains(child)){
                //如果s1已经计算过到此child的经过距离,那么比较出最小的距离
                if((s1.getAllPassedStations(child).size()-1) > shortestPath){
                    //重置S1到周围各站的最小路径
                    s1.getAllPassedStations(child).clear();
                    s1.getAllPassedStations(child).addAll(s1.getAllPassedStations(parent));
                    s1.getAllPassedStations(child).add(child);
                }
            } else {
                //如果s1还没有计算过到此child的经过距离
                s1.getAllPassedStations(child).addAll(s1.getAllPassedStations(parent));
                s1.getAllPassedStations(child).add(child);
            }
        }
        outList.add(parent);
        calculate(s1,s2);//重复计算,往外面站点扩展
    }
    private Station getShortestPath(Station station){//获取参数station到各个站的最短距离,相隔1站,距离为1,依次类推
        int minPatn = Integer.MAX_VALUE;
        Station rets = null;
        for(Station s :station.getOrderSetMap().keySet()){
            if(outList.contains(s)){
                continue;
            }
            LinkedHashSet<Station> set  = station.getAllPassedStations(s);//参数station到s所经过的所有站点的集合
            if(set.size() < minPatn){
                minPatn = set.size();
                rets = s;
            }
        }
        return rets;
    }
    private List<Station> getAllLinkedStations(Station station){//获取参数station直接相连的所有站,包括交叉线上面的站
        List<Station> linkedStaions = new ArrayList<Station>();
        for(List<Station> line : DataBuilder.lineSet){
            if(line.contains(station)){//如果某一条线包含了此站,注意由于重写了hashcode方法,只有name相同,即认为是同一个对象
                Station s = line.get(line.indexOf(station));
                if(s.prev != null){
                    linkedStaions.add(s.prev);
                }
                if(s.next != null){
                    linkedStaions.add(s.next);
                }
            }
        }
        return linkedStaions;
    }
}

UI部分:

FrmQueryLine类

public class FrmQueryLine extends JDialog implements ActionListener {
    private JPanel toolBar = new JPanel();
    private JPanel workPane = new JPanel();
    private JButton btnOk = new JButton("查询");
    private JLabel labelLineName = new JLabel("请输入线路名称:");
    private JTextArea lineinformation=new JTextArea();

    List<String> list=new Line().loadAllLineName();
    String[] ingName = list.toArray(new String[list.size()]);
    private JComboBox cmbIngredient= new JComboBox(ingName);

    public FrmQueryLine(Frame f, String s, boolean b) {
        super(f, s, b);
        workPane.setLayout(null);
        labelLineName.setBounds(10, 9, 129, 19);
        workPane.add(labelLineName);
        cmbIngredient.setBounds(146, 7, 96, 23);
        workPane.add(cmbIngredient);
        btnOk.setBounds(268, 5, 75, 23);
        workPane.add(btnOk);
        lineinformation.setFont(new Font("Monospaced", Font.BOLD, 14));
        lineinformation.setLineWrap(true);//激活自动换行功能
        lineinformation.setWrapStyleWord(false);//激活断行不断字功能
        lineinformation.setBounds(22, 54, 643, 167);
        workPane.add(lineinformation);
        this.getContentPane().add(workPane, BorderLayout.CENTER);
        this.setSize(700, 300);
        //屏幕居中显示
        double width = Toolkit.getDefaultToolkit().getScreenSize().getWidth();
        double height = Toolkit.getDefaultToolkit().getScreenSize().getHeight();
        this.setLocation((int) (width - this.getWidth()) / 2,
                (int) (height - this.getHeight()) / 2);

        this.validate();
        this.btnOk.addActionListener(this);

    }
    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource()==this.btnOk){
            String ingredientName=this.cmbIngredient.getSelectedItem().toString();
            try {
                List<Station> stations=DataBuilder.map.get(ingredientName);
                lineinformation.setText("");
                for(int i=0;i<stations.size();i++) {
                    Station station=stations.get(i);
                    if(i==stations.size()-1)
                        lineinformation.append(station.getName());
                    else
                        lineinformation.append(station.getName()+"<->");
                }
                lineinformation.paintImmediately(lineinformation.getBounds());
            } catch (Exception e1) {
                JOptionPane.showMessageDialog(null, e1.getMessage(), "错误",JOptionPane.ERROR_MESSAGE);
                return;
            }
        }
    }
}

FrmQueryRoute类

public class FrmQueryRoute extends JDialog implements ActionListener {
    private JPanel toolBar = new JPanel();
    private JPanel workPane = new JPanel();
    private JButton btnOk = new JButton("查询");
    private JLabel labelS1 = new JLabel("起始站:");
    private JLabel labelS2 = new JLabel("目标站:");
    private JTextArea lineinformation=new JTextArea();

    private JTextField edtS1 = new JTextField(20);
    private JTextField edtS2 = new JTextField(20);

    public FrmQueryRoute(Frame f, String s, boolean b) {
        super(f, s, b);
        workPane.setLayout(null);
        labelS1.setBounds(26, 9, 67, 15);
        workPane.add(labelS1);
        edtS1.setBounds(103, 6, 126, 21);
        workPane.add(edtS1);
        labelS2.setBounds(265, 9, 67, 15);
        workPane.add(labelS2);
        edtS2.setBounds(361, 6, 126, 21);
        workPane.add(edtS2);
        btnOk.setBounds(519, 5, 77, 23);
        workPane.add(btnOk);
        lineinformation.setFont(new Font("Monospaced", Font.BOLD, 14));
        lineinformation.setLineWrap(true);//激活自动换行功能
        lineinformation.setWrapStyleWord(false);//激活断行不断字功能
        lineinformation.setBounds(36, 33, 908, 204);
        workPane.add(lineinformation);
        this.getContentPane().add(workPane, BorderLayout.CENTER);
        this.setSize(1000, 300);
        // 屏幕居中显示
        double width = Toolkit.getDefaultToolkit().getScreenSize().getWidth();
        double height = Toolkit.getDefaultToolkit().getScreenSize().getHeight();
        this.setLocation((int) (width - this.getWidth()) / 2,
                (int) (height - this.getHeight()) / 2);

        this.validate();
        this.btnOk.addActionListener(this);

    }
    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource()==this.btnOk){
            String S1Name=this.edtS1.getText();
            String S2Name=this.edtS2.getText();
            try {
                int flag1=0,flag2=0;
                for(Station s:DataBuilder.mapOfStation) {
                    if(S1Name.equals(s.getName())) {
                        flag1=1;
                    }
                    if(S2Name.equals(s.getName())) {
                        flag2=1;
                    }
                }
                if(flag1==0) throw new Exception("起始站不存在");
                if(flag2==0) throw new Exception("目标站不存在");
                lineinformation.setText("");//清空JTextArea
                if(S1Name.equals(S2Name))
                    lineinformation.append("目的站与起始站相同");
                else {
                    Subway sw = new Subway();
                    Subway.route.clear();//再次运行清空路线
                    sw.calculate(new Station(S1Name), new Station(S2Name));
                    for(String str:Subway.route)
                        lineinformation.append(str);
                }
                lineinformation.paintImmediately(lineinformation.getBounds());
            } catch (Exception e1) {
                JOptionPane.showMessageDialog(null, e1.getMessage(), "错误",JOptionPane.ERROR_MESSAGE);
                return;
            }
        }
    }
}

 

6.测试用例(将输入输出结果截图提交)

 

 

 

 

 

7.总结

部分抄袭代码:https://blog.csdn.net/wangchsh2008/article/details/46288967

感谢UI指导!

 git:https://github.com/Non-Exited/31701056/tree/master/%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B

posted on 2020-11-04 15:40  31701056  阅读(165)  评论(0)    收藏  举报