一、项目需求
1.该程序能够准确地读出.txt文件中的数据,文件格式简洁易懂、可灵活扩展
2.在某号线路上,能够查询各个站点的信息,输出该号线路上所有站点信息
3.在出发站与目的站之间输出一个最短路径
二、文件存储
三、文件位置
一共三个package:control、main、model
Dijkstra.java(此代码为最短路径算法,虽然叫Dijkstra,但其实并不是Dijkstra的算法;这是最核心的地方,该算法能很好地解决最短路径问题,这段代码是借鉴了网上的代码):
public void calculate(Beansubway s1, Beansubway s2){//计算从s1站到s2站的最短经过路径 String line="初始线"; if(outList.size() == station.totalStaion){ route.add("找到目标站点:"+s2.getStation()+",共经过"+(s1.getAllPassedStations(s2).size()-1)+"站\n"); int flag=0; for(Beansubway station : s1.getAllPassedStations(s2)){ if(station.getLine()==null){//出发站 route.add(station.getStation()+"-->"); } else if(station.getStation().equals(s2.getStation())){//最后1站 if(!station.getLine().equals(line)){ route.add("换乘"+station.getLine()+"\t\n"+"-->"+"到达 "+"-->"+station.getStation()); } else { route.add("到达 " +"-->"+ station.getStation()); } } else if(!station.getLine().equals(line)&&flag==1){//换乘后1站 line=station.getLine(); route.add("换乘"+station.getLine()+"\t\n"+"-->"+station.getStation()+"-->"); } else if(!station.getLine().equals(line)&&flag==0){//第2站 line=station.getLine(); route.add("乘坐"+station.getLine()+"\t\n"+"-->"+station.getStation()+"-->"); flag=1; } else{//其余站 line=station.getLine(); route.add(station.getStation()+"-->"); } } return; } if(!outList.contains(s1)){ outList.add(s1); } //如果起点站的OrderSetMap为空,则第一次用起点站的前后站点初始化之 if(s1.getOrderSetMap().isEmpty()){ List<Beansubway> Linkedstations = getAllLinkedStations(s1); for(Beansubway s : Linkedstations){ s1.getAllPassedStations(s).add(s); } } Beansubway parent = getShortestPath(s1);//获取距离起点站s1最近的一个站(有多个的话,随意取一个) if(parent == s2){ System.out.println("找到目标站点:"+s2+",共经过"+(s1.getAllPassedStations(s2).size()-1)+"站"); for(Beansubway station : s1.getAllPassedStations(s2)){ System.out.print(station.getStation()+"->"); } return; } for(Beansubway 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);//重复计算,往外面站点扩展 }
ui设计:
public FrmMain() { this.setTitle("天津地铁线路"); this.setSize(400, 300); workPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); label=new JLabel("总站点数: "+ station.totalStaion); workPane.add(label); menuSubway.add(menuitemLine); menuitemLine.addActionListener(this); menuSubway.add(menuitemStation); menuitemStation.addActionListener(this); menubar.add(menuSubway); menubar.add(workPane); this.setJMenuBar(menubar); 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.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } }); this.setVisible(true); }
public class FrmSearchLine extends JDialog implements ActionListener{ private JPanel toolBar = new JPanel(); private JPanel workPane = new JPanel(); private Button btnOK = new Button("OK"); private JLabel labelline = new JLabel("查询线路(一号线、二号线、三号线、五号线、六号线、九号线):"); private JTextField edtline = new JTextField(13); private JTextArea edtsubway = new JTextArea(60,110); public FrmSearchLine(FrmMain f, String s, boolean b) { super(f, s, b); toolBar.setLayout(new FlowLayout(FlowLayout.LEFT)); toolBar.add(labelline); toolBar.add(edtline); toolBar.add(btnOK); this.getContentPane().add(toolBar, BorderLayout.NORTH); edtsubway.setFont(new Font("Monospaced", Font.BOLD, 14)); edtsubway.setLineWrap(true); //激活自动换行功能 edtsubway.setWrapStyleWord(false); workPane.add(edtsubway); this.getContentPane().add(workPane, BorderLayout.CENTER); this.setSize(1000, 600); 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); this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { } }); }
public class FrmSearchStation extends JDialog implements ActionListener{ private JPanel toolBar = new JPanel(); private JPanel workPane = new JPanel(); private Button btnSearch = new Button("Search"); private JLabel labelstart = new JLabel("起点:"); private JLabel labelend= new JLabel("终点:"); private JTextField edtstart = new JTextField(13); private JTextField edtend = new JTextField(13); private JTextArea edtsubway = new JTextArea(60,80); public FrmSearchStation(FrmMain f, String s, boolean b) { super(f, s, b); toolBar.setLayout(new FlowLayout(FlowLayout.LEFT)); toolBar.add(labelstart); toolBar.add(edtstart); toolBar.add(labelend); toolBar.add(edtend); toolBar.add(btnSearch); this.getContentPane().add(toolBar, BorderLayout.NORTH); edtsubway.setFont(new Font("Monospaced", Font.BOLD, 14)); edtsubway.setLineWrap(true); //激活自动换行功能 edtsubway.setWrapStyleWord(false); workPane.add(edtsubway); this.getContentPane().add(workPane, BorderLayout.CENTER); this.setSize(800, 600); 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.btnSearch.addActionListener(this); this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { } }); }
Beansubway.java(是对于线路上变量函数的存储结构):
private String line; private String station; public Beansubway prev; public Beansubway next; private Map<Beansubway,LinkedHashSet<Beansubway>> orderSetMap = new HashMap<Beansubway,LinkedHashSet<Beansubway>>(); public String getLine() { return line; } public void setLine(String line) { this.line = line; } public String getStation() { return station; } public void setStation(String station) { this.station = station; } public Beansubway(String station) { this.station = station; } public LinkedHashSet<Beansubway> getAllPassedStations(Beansubway station) { if(orderSetMap.get(station) == null){ LinkedHashSet<Beansubway> set = new LinkedHashSet<Beansubway>(); set.add(this); orderSetMap.put(station, set); } return orderSetMap.get(station); } public Map<Beansubway, LinkedHashSet<Beansubway>> getOrderSetMap() { return orderSetMap; }
Beanlujing.java(对于经过站点的存储)
private String name; private List<Beansubway> passStations;//经过的站点 public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Beansubway> getPassStations() { return passStations; } public void setPassStations(List<Beansubway> passStations) { this.passStations = passStations; } public List<String> loadAllLineName(){//罗列所有线路名字 List<String> list=new ArrayList<>(); for(int i=0;i<station.AllLine.size();i++){ list.add(station.AllLine.get(i).getName()); } return list; }
四、运行方法与测试
需求1:读取subway.txt文件的语句:
需求2:输出指定线路的所有站点
需求3:输出两站点之间的最短路径
1.起点站不存在
2.终点站不存在
3.起点站与终点站相同
五、体会
由于是首次做一个感到如此艰难的个人项目,相比于暑期的短学期项目,这个明显难了很多,对于个人能力要求上了不止一个大档次。其次,刚开始写代码,一直卡在最短路径算法这个方向,后来想到了dijkstra算法,但是对这个算法又并没有那么熟悉,所以在这个个人项目中,借鉴了网上的其他算法代码,然后自己设计了一些UI元素,并且能够理解算法大致内容。