地铁最短路径代码分析
相关链接:
https://github.com/jindsad/subwayDijkstra
实验要求说明:
根据实验要求,要实现5块部分。
1.导入txt中储存的地铁线路。
2.通过地铁线路生成地铁图,并记录每条线路的站点。
3.通过Dijkstra算法算出最短路径,储存在列表中。
4.遍历路径列表,记录线路转变,存入字符串。
5.将最短路径字符串导出txt。
模块分析:
保存站点和线路的类
站点类名Vertex包含属性有名字,相邻节点,所属线路,距离起始点最短路径,在最短路径中的上一个节点,是否已经被遍历。
public class Vertex {
public final String name;
public ArrayList<Vertex> neighbour=new ArrayList<Vertex>();
public ArrayList<String> line=new ArrayList<String>();
private int adjuDist;
private Vertex parent;
private boolean known=false;
}
线路类line包含线路名字,拥有的站点。
public class line {
public final String name;
public List<String> station;
//=new ArrayList<String>()
public line(String name,List<String> station){
this.name = name;
this.station = station;
}
}
地铁输入txt文件格式
1号线:苹果园 .. 2号线:西直门 .. 4号线:宋河桥北 .. 5号线:宋家庄 ....
导入txt中储存的地铁线路
通过txt路径将地铁按行保存在List列表中,一行为一条线路。
方法名inputmapname
public List<String> inputmapname(String mapname){
List<String> list = new ArrayList<String>();
String line =new String();
try (FileReader reader = new FileReader(mapname);
BufferedReader br = new BufferedReader(reader);
) {
while ((line = br.readLine()) != null) {
if (line.lastIndexOf("---") < 0) {
list.add(line);
}
}
return list;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
通过地铁线路生成地铁图,并记录每条线路的站点
向线路添加站点
通过inputmapname方法将线路字符串存在list中,先用split将字符串按:分割,str[0]为名称,str[1]为站点。再将str[1]按“ ”分割得出每个站点名,将站点名保存在line类中,并用一个List station记录所有站点。station中的所有Vertex先不记录线路信息和相邻节点信息。
List<String> map=a.inputmapname(inputname);
for(int b=0;b<map.size();b++) {
//向线路加入站点
List<String> s=new ArrayList<String>();
String[] str;
str = map.get(b).split(":");
String[] sta;
sta = str[1].split(" ");
for(int st=0;st<sta.length;st++) {
s.add(sta[st]);
}
line li=new line(str[0],s);
line.add(li);
for(int st=0;st<sta.length;st++) {
Vertex ve=new Vertex(sta[st]);
int t=0;
for(int op=0;op<station.size();op++) {
if(station.get(op).name.equals(sta[st])) {
t=1;
break;
}
}
if(t==0)station.add(ve);
}
}
向站点传入相邻节点信息和所属站点
在传入线路时,已经将站点名存入station中,需要向站点添加相邻站点和线路,将txt文件重新导入,重新得到各线路站点,
将得到的站点遍历和station中进行比较,寻找出名字为sta[st+1]的站点和sta[st-1]的站点。并将寻找出String[st]对应的站点,将String[st+1]和String[st-1]对应的站点加入相邻站点中,并将站点对应的线路存入站点中
List<String> map=a.inputmapname(inputname);
for(int b=0;b<map.size();b++) {
//向线路加入站点
List<String> s=new ArrayList<String>();
String[] str;
str = map.get(b).split(":");
String[] sta;
sta = str[1].split(" ");
for(int st=0;st<sta.length;st++) {
int nu1=-1;
int nu2=-1;
for(int st1=0;st1<station.size();st1++) {
if(st>0&&station.get(st1).toName().equals(sta[st-1])) {
nu1=st1;
}
if(st<sta.length-1&&station.get(st1).toName().equals(sta[st+1])) {
nu2=st1;
}
if(nu2!=-1&&nu1!=-1)break;
}
for(int st1=0;st1<station.size();st1++) {
if(station.get(st1).toName().equals(sta[st])) {
if(nu1!=-1)station.get(st1).neighbour.add(station.get(nu1));
if(nu2!=-1)station.get(st1).neighbour.add(station.get(nu2));
station.get(st1).line.add(str[0]);
break;
}}}}
去除一个节点的重复线路

北京线路中会存在环形线路,我将这样的线路头尾用一个站点保存,使其构成环路,所以对站点添加线路名字时,会出现同一站点线路重复,所以需要去重,使用方法trimList去除相同元素。
private static ArrayList trimList(ArrayList list) {
ArrayList list2 = new ArrayList();
for (int i = list.size() - 1; i >= 0; i--) {
Object o = list.get(i);
if (list2.indexOf(o) == -1) {
list2.add(0, o);
}
}
return list2;
}
通过Dijkstra算法算出最短路径,储存在列表中
用递归,当站点为空返回空,对站点v的相邻站点进行遍历,如果相邻点没有被访问过,就将其路径更改为v.getAdjuDist()+1 ,其父节点为v,如果相邻点的最短路径比v.getAdjuDist()+1 小这不做更改,如果相邻节点的最短路径比v.getAdjuDist()+1 ,更新最短路径为v.getAdjuDist()+1 。把所有相邻节点递归,直到所有节点遍历完成。
private void updateChildren(Vertex v)
{
if (v==null) {
return;
}
if(v.neighbour==null||v.neighbour.size()==0) {
return;
}
List<Vertex> childrenList = new LinkedList<Vertex>();
for(int a=0;a<v.neighbour.size();a++){
if(v.getParent()==null||!v.getParent().equals(v.neighbour.get(a))) {
Vertex childVertex=v.neighbour.get(a);
if(!childVertex.isKnown())
{
childVertex.setKnown(true);
childVertex.setAdjuDist(v.getAdjuDist()+1);
childVertex.setParent(v);
childrenList.add(childVertex);
}
int nowDist = v.getAdjuDist()+1;
if(nowDist>=childVertex.getAdjuDist())
{
continue;
}
else {
childVertex.setAdjuDist(nowDist);
childVertex.setParent(v);
childrenList.add(childVertex);
}
}
}
for(Vertex vc:childrenList)
{
updateChildren(vc);
}
}
遍历路径列表,记录线路转变,存入字符串。
通过dijkstraTravasal输出最短路径站点,需要判断转站点。遍历每个ar的站点,用xian储存现在站点的线路,判断每个站点的前一个节点和后一个节点,如果站点改变则转成下一站点的线路,如果现有线路的xian改变,则也进行转站。将站点和转站线路保存在pa中用outputmap返回。
ar=dik.dijkstraTravasal(station, place1, place2);
String pa=String.valueOf(ar.size())+"\r\n";
String xian="";
for(int num=0;num<ar.get(ar.size()-1).line.size();num++) {
for(int num1=0;num1<ar.get(ar.size()-2).line.size();num1++) {
if(ar.get(ar.size()-1).line.get(num).equals(ar.get(ar.size()-2).line.get(num1))) {
xian=ar.get(ar.size()-1).line.get(num);
break;
}
if(!xian.equals(""))break;
}
}
for(int num=ar.size()-1;num>=0;num--) {
int y=0;
pa=pa+ar.get(num).toName()+"\r\n";
if(ar.get(num).line.size()>1&&num!=0&&num!=ar.size()-1){
for(int num1=0;num1<ar.get(num-1).line.size();num1++) {
for(int num2=0;num2<ar.get(num+1).line.size();num2++) {
if(ar.get(num-1).line.get(num1).equals(ar.get(num+1).line.get(num2))) {
y=1;
break;
}
if(y==1)break;
}
}
for(int num2=0;num2<ar.get(num-1).line.size();num2++) {
if(ar.get(num-1).line.get(num2).equals(xian)) {
break;
}
if(num2==ar.get(num-1).line.size()-1)y=0;
}
if(y==0) {
String hua="";
for(int num1=0;num1<ar.get(num).line.size();num1++) {
for(int num2=0;num2<ar.get(num-1).line.size();num2++) {
if(ar.get(num).line.get(num1).equals(ar.get(num-1).line.get(num2))) {
hua=ar.get(num-1).line.get(num2);
xian=hua;
break;
}
if(y==1)break;
}
}
pa=pa+hua+"\r\n";
}
}
}
-a输出line线路
for(int b=0;b<line.size();b++) {
if(line1.equals(line.get(b).name)) {
for(int b1=0;b1<line.get(b).station.size();b1++) {
line2=line2+" "+line.get(b).station.get(b1);
}
break;
}
}
程序结果展示
输入:
-b 良乡大学城 双桥 -map C:\Users\Shinelon\eclipse-workspace\软件工程个人作业\src\软件工程个人作业\北京地铁图1.txt -o C:\Users\Shinelon\eclipse-workspace\软件工程个人作业\src\软件工程个人作业\station.txt
输出:

