北京地铁最短路径规划

项目介绍

1.主要功能

提供一副地铁线路图,计算指定两站之间最短(最少经过站数)乘车路线;输出指定地铁线路的所有站点。以北京地铁为例,地铁线路信息保存在data.txt中,格式如下:

 

地铁线路总数
线路名1 站名1 站名2 站名3 ...
线路名2 站名1 站名2 站名3 ...
线路名3 站名1 站名2 站名3 ......

 

 

 

 实现以下功能:

  • 实现地铁线路信息图的导入
  • 实现查询功能,查询指定地铁线路之间的信息
  • 实现从出发地到目的地之间最短路径规划,并供使用者使用

2.实现语言

Java

3.实现算法

Floyd算法

通过一个图的权值矩阵求出它的每两点间的最短路径矩阵。 
从图的带权邻接矩阵A=[a(i,j)] n×n开始,递归地进行n次更新,即由矩阵D(0)=A,按一个公式,构造出矩阵D(1);又用同样地公式由D(1)构造出D(2);……;最后又用同样的公式由D(n-1)构造出矩阵D(n)。矩阵D(n)的i行j列元素便是i号顶点到j号顶点的最短路径长度,称D(n)为图的距离矩阵,同时还可引入一个后继节点矩阵path来记录两点间的最短路径。

4.类职责划分

  • Floyd:Floyd算法的具体实现。
  • Main:读入数据和启动程序。
  • Graph:用于储存Floyd算法中将会用到的图的邻接矩阵,即地铁站点图。
  • ui:提供用户交互界面。
  • Line:线路类。
  • Station:站点类。

5、核心代码

(1)Main类读入数据驱动程序

 

package subway;

 

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

 

public class Main {
public static void main(String[] args) {

 

Graph G=new Graph();
String pathname = ".\\station.txt";
ArrayList<String> Information=new ArrayList<String>();
ArrayList<Line> allLines=new ArrayList<Line>();


try (
FileReader reader = new FileReader(pathname);
BufferedReader br = new BufferedReader(reader)
) {
String line;
while ((line = br.readLine()) != null) {
Information.add(line);
}
}
catch (IOException e) {
e.printStackTrace();
}


for(int i=0;i<Information.size();i+=2) {
Line lines =new Line();
String LineName=Information.get(i);
lines.setName(LineName);
String[] stations=Information.get(i+1).split("\\s+");

for(String s:stations) {
Station curStation=new Station();
curStation.setLine(LineName);
curStation.setName(s);
lines.getSubwayStation().add(curStation);
}

allLines.add(lines);
}

G.InitGraph(allLines);
new ui(G,allLines).setVisible(true);;

}
}

 

(2)station类存储站点信息


public class Station {
private String Line;
private String Name;
private boolean transfer = false;



public String getLine() {
return Line;
}
public void setLine(String line) {
Line = line;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public boolean equals(Station s){
if(this.Name.equals(s.getName()))
return true;
return false;
}
public boolean isTransfer() {
return transfer;
}
public void setTransfer(boolean transfer) {
this.transfer = transfer;
}


}

(3)Line类存储线路信息

 

package subway;

 

import java.util.ArrayList;
import java.util.List;

 

public class Line {
private String Name;
private ArrayList<Station> SubwayStation=new ArrayList<Station>();

public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public ArrayList<Station> getSubwayStation() {
return SubwayStation;
}
public void setSubwayStation(ArrayList<Station> subwayStation) {
SubwayStation = subwayStation;
}
public Line PrintLine(String name,List<Line> allLines) {
for(Line s:allLines) {
if(name.equals(s.getName())) {
return s;
}
}
return null;
}
public boolean HaveStation(String name) {
for(Station s:SubwayStation) {
if(s.getName().equals(name))
return true;
}
return false;
}
}

 

 

 

(4)Floyd类 实现主要算法

package subway;

import java.util.ArrayList;
import java.util.List;

public class Floyd {
private List<Station> Stationlist = new ArrayList<Station>();
public ArrayList<String> getShortestPath(String s1,String s2,Graph G,List<Line> Lines) throws Exception{
int size=G.getMax();
int[][] path=new int[size][size];
int[][] d=G.getDist();
for(int i=0;i<size;i++)
for(int j=0;j<size;j++){
path[i][j]=j;
}

for(int k=0; k<size; k++){
for(int i=0; i<size; i++){
for(int j=0; j<size; j++) {
if(d[i][k]!=-1&&d[k][j]!=-1) {
if(d[i][j]>d[i][k]+d[k][j]) {
d[i][j]=d[i][k]+d[k][j];
path[i][j]=path[i][k];
}
}
}
}
}
int start=G.findStation(s1);
int end=G.findStation(s2);
if(start==-1)
throw new Exception("起点不存在");
if(end==-1)
throw new Exception("终点不存在");
if(start==end)
throw new Exception("起点和终点不能相同");
ArrayList<String> result=new ArrayList<String>();
if(start!=-1&&end!=-1) {
int count=0;
int temp=path[start][end];
Stationlist.add(G.getStations().get(start));
while(temp!=end ) {
Stationlist.add(G.getStations().get(temp));

temp=path[temp][end];
}
Stationlist.add(G.getStations().get(temp));
result.add(Integer.toString(Stationlist.size()));
result.add(Stationlist.get(0).getName());
for(int i=1;i<Stationlist.size()-1;i++) {
result.add(Stationlist.get(i).getName());
if(Stationlist.get(i).isTransfer()==true) {
String res=IsTransferLine(Stationlist.get(i-1).getName(),Stationlist.get(i).getName(),Stationlist.get(i+1).getName(),Lines);
if(res!=null)
result.add(res);

}
}
result.add(Stationlist.get(Stationlist.size()-1).getName());

}

return result;
}
public String IsTransferLine(String pre,String mid,String next,List<Line> allLines) {
String start=null;
String end=null;
for(Line s:allLines) {
if(s.HaveStation(pre)&&s.HaveStation(mid))
start=s.getName();
if(s.HaveStation(mid)&&s.HaveStation(next))
end=s.getName();
}
if(!start.equals(end))
return end;

return null;
}
}

(5)Graph类 构造邻接矩阵

package subway;

import java.util.ArrayList;
import java.util.List;

public class Graph {
private int [][] Dist =new int[500][500];
private int Max;
public List<Station> Stations = new ArrayList<Station>();
public void InitGraph(List<Line> Lines) {
for(int i=0;i<Lines.size();i++) {
List<Station> Stations=Lines.get(i).getSubwayStation();
for(int j=0;j<Stations.size();j++) {
int index=this.getIndex(Stations.get(j));
if(index==-1)
Stations.add(Stations.get(j));
else if(index!=-1) {
Stations.get(index).setTransfer(true);
Lines.get(i).getSubwayStation().get(j).setTransfer(true);
}
}
}


Max=Stations.size();

for(int i=0;i<Max;i++)
for(int j=0;j<Max;j++){
if(i==j)
Dist[i][j]=0;
else
Dist[i][j]=500;
}


for(Line line:Lines) {
List<Station> Stations=line.getSubwayStation();
for(int j=0;j<Stations.size()-1;j++) {
int start =this.getIndex(Stations.get(j));
int end =this.getIndex(Stations.get(j+1));

Dist[start][end]=1;
Dist[end][start]=1;
}
}
}
public int getIndex(Station s) {
for(int i=0;i<Stations.size();i++)
if(Stations.get(i).getName().equals(s.getName()))
return i;
return -1;
}
public int findStation(String name) {
for(int i=0;i<Stations.size();i++)
if(Stations.get(i).getName().equals(name))
return i;
return -1;
}
public int getMax() {
return Max;
}
public void setMax(int max) {
Max = max;
}
public int[][] getDist() {
return Dist;
}
public void setDist(int[][] dist) {
Dist = dist;
}
public List<Station> getStations() {
return Stations;
}
public void setStations(List<Station> stations) {
Stations = stations;
}

}

(6)ui类交互界面

package subway;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableModel;


import subway.Floyd;
import subway.Graph;
import subway.Station;
import subway.Line;

 

public class ui extends JDialog implements ActionListener {

private ArrayList<Line> allLines=new ArrayList<Line>();

private Graph G=new Graph();

private JPanel toolBar = new JPanel();
private JPanel workPane = new JPanel();
private JButton btnFindLine = new JButton("查询线路");
private JButton btnFindWay = new JButton("查询最短路径");

private JLabel labelLine = new JLabel("线路号:");
private JLabel labelStart = new JLabel("起点:");
private JLabel labelEnd = new JLabel("终点:");


private JTextField edtLine = new JTextField(50);
private JTextField edtStart = new JTextField(50);
private JTextField edtEnd = new JTextField(50);
private JList<String> list=new JList();
private JScrollPane scrollPane=new JScrollPane(list);


private Object tblStationData[][];
DefaultTableModel tabStationModel=new DefaultTableModel();
private JTable dataTableStation=new JTable(tabStationModel);
private JScrollPane StationPane=new JScrollPane(this.dataTableStation);

public ui(Graph G,ArrayList<Line> Lines) {
this.allLines=Lines;
this.G=G;

workPane.setLayout(null);
workPane.setBounds(0,0,400,250);

btnFindLine.setBounds(10, 40, 160, 20);
workPane.add(btnFindLine);
btnFindWay.setBounds(300, 70, 160, 20);
workPane.add(btnFindWay);

labelLine.setBounds(10, 10, 60, 20);
workPane.add(labelLine);
edtLine.setBounds(70, 10, 100, 20);
workPane.add(edtLine);

labelStart.setBounds(300, 10, 60, 20);
workPane.add(labelStart);
edtStart.setBounds(360, 10, 100, 20);
workPane.add(edtStart);

labelEnd.setBounds(300, 40, 60, 20);
workPane.add(labelEnd);
edtEnd.setBounds(360, 40, 100, 20);
workPane.add(edtEnd);

scrollPane.setBounds(10,100,160,300);
workPane.add(scrollPane);

StationPane.setBounds(300,100,160,300);
workPane.add(StationPane);

this.getContentPane().add(workPane, BorderLayout.CENTER);
this.setSize(600, 500);

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.btnFindLine.addActionListener(this);
this.btnFindWay.addActionListener(this);

}
public void actionPerformed(ActionEvent e) {
if(e.getSource()==this.btnFindLine) {
String LineName=this.edtLine.getText();

try {
Line result=new Line().PrintLine(LineName, allLines);
if(result==null) throw new Exception("线路不存在");
String [] stations= new String[result.getSubwayStation().size()];
for(int i=0;i<result.getSubwayStation().size();i++) {
stations[i]=result.getSubwayStation().get(i).getName();
}
this.list.setListData(stations);
}

catch (Exception e1) {
JOptionPane.showMessageDialog(null, e1.getMessage(), "错误",JOptionPane.ERROR_MESSAGE);
return;
}
}
else if(e.getSource()==this.btnFindWay){
String start=this.edtStart.getText();
String end=this.edtEnd.getText();
try {

ArrayList<String> result=new Floyd().getShortestPath(start, end, G, allLines);
tblStationData = new Object[result.size()][1];
for(int i=0;i<result.size();i++) {
tblStationData[i][0]=result.get(i);
}
Object[] msg= {"最短路径"};
tabStationModel.setDataVector(tblStationData,msg);
this.dataTableStation.validate();
this.dataTableStation.repaint();

} catch (Exception e1) {
JOptionPane.showMessageDialog(null, e1.getMessage(), "错误",JOptionPane.ERROR_MESSAGE);
return;
}
}

}


}

6、测试样例

(1)输入站点不正确:

 

 

 

 

 (2)起点终点相同

 

(3)正常线路

 

 (4)输出线路

 

 

 7、总结

本次实践发现自己对java还是有诸多问题,各种数据结构使用的并不熟练。除了对自身代码能力的了解,也对软件工程有了更深的了解从需求到实现,工程的规划都有了更深的理解。

本次实验已上传git,https://github.com/hyrlzy666/subway

posted @ 2020-11-04 23:19  hyrlzy  阅读(327)  评论(0)    收藏  举报