热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

图的最短路径java_地铁线路最短路径(JAVA实现)

项目综述提供一副地铁线路图,计算指定两站之间最短(最少经过站数)乘车路线;输出指定地铁线路的所有站点。以北京地铁为例,地铁线路信息保存在d

项目综述

6c3f258d2e4d136907687825b3b9a325.png

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

地铁线路总数

线路名1 站名1 站名2 站名3 ...

线路名2 站名1 站名2 站名3 ...

线路名3 站名1 站名2 站名3 ......

一、需求分析

1.该程序能够准确地读出.txt文件中的数据,文件格式简洁易懂、可灵活扩展

2.在某号线路上,能够查询各个站点的信息,输出该号线路上所有站点信息

3.在出发站与目的站之间输出一个最短路径

二、实现语言

Java

三、实现算法

Floyd算法

四、类职责划分

1.SubwayAssistantStarter类

程序入口

2.GetData类

从data.txt中读取数据并存储各条线路和各个站点

3.Line类

privateString name;private List stations = new ArrayList();//该线路上的所有站点

//已省略Getter & Setter

4.Map类

private int[][] subwayline;//存储线路private static List stations;//存储所有站点private int[][] path;//存储路径

//已省略Getter & Setter

5.Result类

private static final int max = 999999;//最大距离

private int[][] ShortestPath;//最短路径

private int[][] ShortestDis;//最短距离

//已省略Getter & Setter

6.FrmMain类

ui主界面,包括功能选择和显示北京地铁线路背景图

7.FrmLine类 & FrmShowStations类

ui分页面

FrmLine类:用户需输入格式正确的线路名

FrmShowStation类:用户输入格式正确的线路名后弹窗显示具体线路信息

8.FrmShortestPath类 & FrmShowShortestPath类

ui分页面

FrmShortestPath类:用户输入格式正确的站点名

FrmShowShortestPath类:用户输入正确后弹窗显示两站间最短路径具体信息

五、核心代码

1.读取data.txt中的数据

public class GetData {//读取.txt文件中的信息

public static int linenum = 0;

@SuppressWarnings("null")public GetData(String pathname, List lines) throwsIOException{//读文件准备

File file = newFile(pathname);

InputStreamReader rdr= new InputStreamReader(newFileInputStream(file));

BufferedReader br= newBufferedReader(rdr);try{

String content=null;while((content=br.readLine())!=null) {

linenum++;

Line newline= newLine();

List line = new ArrayList();

String[] station_single= content.split(" ");

String linename= station_single[0];//第一个元素为线路名

for(int i=1;i

if(i==station_single.length-1 && station_single[i].equals(station_single[1]))//处理环线

continue;

line.add(station_single[i]);

}

newline.setName(linename);

newline.setStations(line);

lines.add(newline);

}

br.close();

}catch(IOException e) {

e.printStackTrace();

}finally{if (br == null)try{

br.close();

}catch(IOException e) {

e.printStackTrace();

}

}

}

}

2.Floyd算法求最短路径

public classResult {private static final int max = 999999;private int[][] ShortestPath;private int[][] ShortestDis;public Result(int[][] G) {this.ShortestPath = new int[G.length][G.length];this.ShortestDis = new int[G.length][G.length];for(int i=0;i

}

}//Floyd核心算法

for(int k=0;kthis.ShortestDis[i][k]+this.ShortestDis[k][j]) {this.ShortestDis[i][j]=this.ShortestDis[i][k]+this.ShortestDis[k][j];this.ShortestPath[i][j]=this.ShortestPath[i][k];

}

}

}

}

3.初始化整个地图

public Map(List stations) {//初始化整个地图

this.stations =stations;this.subwayline = new int[stations.size()][stations.size()];this.path = new int[stations.size()][stations.size()];for(int i=0;i

subwayline[i][j]= 999999;

subwayline[j][i]= 999999;

}

}

}

4.主页面显示功能与北京地铁线路背景图

public class FrmMain extends JFrame implementsActionListener{private static final long serialVersionUID = 1L;private JMenuBar menubar=newJMenuBar();private JPanel statusBar = newJPanel();private JMenu menu_Manager=new JMenu("功能");

JFrame jf&#61;newJFrame();private JMenuItem menuItem_Line&#61;new JMenuItem("查询线路");private JMenuItem menuItem_ShortestPath&#61;new JMenuItem("查询最短路径");private static List lines &#61; new ArrayList<>();//存储.txt中的所有数据

private List stations &#61; new ArrayList();//存储所有站点

public FrmMain() throwsIOException {//读文件

String filepath &#61; "E:\\Software Engineering\\data.txt";

GetData data&#61; newGetData(filepath,lines);//北京地铁图片

JLabel jl3&#61;new JLabel(new ImageIcon("E:\\Software Engineering\\subway.jpg"));

jf.add(jl3);

jl3.setBounds(0, 100, 80, 60);

jf.pack();

jf.setVisible(true);this.setTitle("北京地铁小助手");

menu_Manager.add(menuItem_Line);

menuItem_Line.addActionListener(this);

menu_Manager.add(menuItem_ShortestPath);

menuItem_ShortestPath.addActionListener(this);

menubar.add(menu_Manager);

statusBar.setLayout(newFlowLayout(FlowLayout.LEFT));

JLabel label&#61;new JLabel("欢迎使用北京地铁小助手^^");

statusBar.add(label);this.getContentPane().add(statusBar,BorderLayout.SOUTH);this.addWindowListener(newWindowAdapter(){public voidwindowClosing(WindowEvent e){

System.exit(0);

}

});this.setVisible(true);this.setJMenuBar(menubar);

}public voidactionPerformed(ActionEvent e) {if(e.getSource()&#61;&#61;this.menuItem_Line){

FrmLine dlg&#61;new FrmLine(this,"查询线路",true,lines);

dlg.setVisible(true);

}else if(e.getSource()&#61;&#61;this.menuItem_ShortestPath){

FrmShortestPath dlg&#61;new FrmShortestPath(this,"查询最短路径",true,lines,stations);

dlg.setVisible(true);

}

}

5.在查询页面处理最短路径

public class FrmShortestPath extends JDialog implementsActionListener{private List lines2 &#61; new ArrayList<>();//存储.txt中的所有数据

privateResult result;privateMap map;private List list1 &#61; new ArrayList<>(); //存储经过单个站点的地铁线的名字&#xff0c;以列表储存

private List> lists &#61; new ArrayList<>(); //存储经过所有站点的地铁线的名字&#xff0c;将list1依次添加进lists中

private List passStation &#61; new ArrayList<>(); //储存经过站点在数组中的下标

private JPanel toolBar &#61; newJPanel();private JPanel workPane &#61; newJPanel();private Button btnOk &#61; new Button("查询");private JTextField edtStart &#61; new JTextField(20);private JTextField edtEnd &#61; new JTextField(20);private JLabel labelStart &#61; new JLabel("起点:");private JLabel labelEnd &#61; new JLabel("终点:");private JLabel labelTip &#61; new JLabel("请输入您要查询的起点和终点^^");public FrmShortestPath(FrmMain frmMain, String s, boolean b, List lines, Liststations) {super(frmMain,s,b);

lines2.addAll(lines);

toolBar.setLayout(newFlowLayout(FlowLayout.RIGHT));

toolBar.add(btnOk);this.getContentPane().add(toolBar, BorderLayout.SOUTH);

workPane.add(labelStart);

workPane.add(edtStart);

workPane.add(labelEnd);

workPane.add(edtEnd);

workPane.add(labelTip);this.getContentPane().add(workPane, BorderLayout.CENTER);this.setSize(280, 150);double width &#61;Toolkit.getDefaultToolkit().getScreenSize().getWidth();double height &#61;Toolkit.getDefaultToolkit().getScreenSize().getHeight();this.setLocation((int) (width - this.getWidth()) / 2,

(int) (height - this.getHeight()) / 2);this.validate();this.btnOk.addActionListener(this);this.addWindowListener(newWindowAdapter() {public voidwindowClosing(WindowEvent e) {//System.exit(0);

}

});//把所有站点加入stations中

for(int i&#61;0;i

stations.addAll(lines.get(i).getStations());

}

map&#61; new Map(stations);//此map非彼map//初始化各个站点间的距离为1

for(int i&#61;0;i

map.initDis(lines.get(i).getStations().get(j), lines.get(i).getStations().get(j&#43;1));

}

}//求最短路径

result &#61; newResult(map.getSubwayline());

}

&#64;Overridepublic voidactionPerformed(ActionEvent e) {if(e.getSource()&#61;&#61;this.btnOk) {int flag1&#61;-1;int flag2&#61;-1;

String start&#61; this.edtStart.getText();

String end&#61; this.edtEnd.getText();

flag1&#61;FrmMain.isStation(start);

flag2&#61;FrmMain.isStation(end);if(start&#61;&#61;null || start.equals("") || end&#61;&#61;null || end.equals(""))try{throw newException();

}catch(Exception e1) {

JOptionPane.showMessageDialog(null, "起点/终点不能为空&#xff01;","错误",JOptionPane.ERROR_MESSAGE);return;

}else if(flag1<0 || flag2<0){try{throw newException();

}catch(Exception e1) {

JOptionPane.showMessageDialog(null, "起点/终点不存在&#xff01;","错误",JOptionPane.ERROR_MESSAGE);return;

}

}else if(start.equals(end)) {try{throw newException();

}catch(Exception e1) {

JOptionPane.showMessageDialog(null, "起点和终点不能相同&#xff01;","错误",JOptionPane.ERROR_MESSAGE);return;

}

}else{//查询shortest path

int i &#61;map.getIndex(start);int j &#61;map.getIndex(end);int shortest &#61; result.getMinDis(i,j);//需修改

if(shortest &#61;&#61; 999999) {try{throw newException();

}catch(Exception e1) {

JOptionPane.showMessageDialog(null, "两站点不可达&#xff01;","错误",JOptionPane.ERROR_MESSAGE);return;

}

}

shortest&#43;&#43;;

String path&#61; start&#43;"到"&#43;end&#43;"需经过"&#43;shortest&#43;"个站\n";

passStation&#61; result.indexToList(i,j);//存储最短路径

for(int k&#61;0;k

List list &#61; new ArrayList<>();

path&#43;&#61;(map.getName(passStation.get(k))&#43;"(");//System.out.println(path);

for(Line l:lines2) {int flag&#61;0;for(String name:l.getStations()) {

System.out.println(map.getName(passStation.get(i)));if(map.getName(passStation.get(i)).equals(name)){

path&#43;&#61;(l.getName()&#43;" ");

list.add(l.getName());if(!list1.contains(name)) {

list1.add(name);

flag&#61;1;

}

}

}if(flag&#61;&#61;1) lists.add(list);

}

}

path&#43;&#61;")";

path&#43;&#61;"\n";//存储换乘车站

List transfer &#61; new ArrayList<>();for(int p&#61;2;p

flag&#61;1;break;

}

}if(flag&#61;&#61;0) {if(!transfer.contains(list1.get(p-1))); transfer.add(list1.get(p-1));

}

}

path&#43;&#61;"\n";

path&#43;&#61;"需要换乘"&#43;transfer.size()&#43;"次&#xff1a;";for(int a&#61;0;a

path&#43;&#61;(transfer.get(a)&#43;" ");

}

path&#43;&#61;"\n";

FrmShowShortestPath dlg&#61;new FrmShowShortestPath(this,"最短路径详情",true,path);

dlg.setVisible(true);

}

}

}

}

六、测试用例

1.主界面

包括功能与北京地铁线路背景图

0318fa584596ad4561357aa1d93ec81d.png

2.查询线路

70dd3eb89684189ed010e03e503bd4e6.png

3.查询线路·输入为空

d815dd83a3c9bb69ea73f071fa5f10fa.png

4.查询线路·输入不存在的线路

ca2f0c1b55360cfe50bad3e2221713b6.png

5.查询最短路径·同线路

661a26406869e981070ad8181f7877d0.png

6.查询最短路径·远站需换乘

8cb2a539eb292ca380441ed03828d0fe.png

7.查询最短路径·起点/终点为空

c4118345c4a2f66a01ea271edb9cc4c0.png

6b42553bb26d2aafca624dfb1e47f21e.png

8.查询最短路径·输入站点不存在

191af632235bb6b5bdf5f71d6db27116.png

9.查询最短路径·起点终点相同

bca638c6dd24e139b2cb4e8588e66423.png

七、总结

1.在上一次的需求分析中原本打算用Dijstra算法&#xff0c;但是在写代码的过程中发现了Floyd算法更易实现&#xff0c;于是就果断跑路Floyd算法了&#xff0c;究其原因应该是需求分析不够深入&#xff0c;没有进一步结合代码实现来思考。

2.写代码的过程中&#xff0c;意识到多个UI界面弹窗之间传参数的麻烦之处&#xff0c;经过这一次的锻炼&#xff0c;对JAVA类与类之间传参数有了更好的理解。

3.认识到自己对JAVA还有许多不了解的“简便方法”&#xff0c;在本次写博客的过程中在CSDN中获益匪浅&#xff0c;希望以后也是多多锻炼&#xff0c;继续在CSND和Baidu中学习更多的知识。

4.至于前端UI&#xff0c;我还是以较为“偷懒”的方式用了在暑假短学期学到的JAVA Swing&#xff0c;算是对之前学习内容的一个复习与巩固叭。

5.算是第一次写这么完整的技术博客&#xff0c;也是一次不可多得的实战经验呢^^



推荐阅读
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • Week04面向对象设计与继承学习总结及作业要求
    本文总结了Week04面向对象设计与继承的重要知识点,包括对象、类、封装性、静态属性、静态方法、重载、继承和多态等。同时,还介绍了私有构造函数在类外部无法被调用、static不能访问非静态属性以及该类实例可以共享类里的static属性等内容。此外,还提到了作业要求,包括讲述一个在网上商城购物或在班级博客进行学习的故事,并使用Markdown的加粗标记和语句块标记标注关键名词和动词。最后,还提到了参考资料中关于UML类图如何绘制的范例。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • React项目中运用React技巧解决实际问题的总结
    本文总结了在React项目中如何运用React技巧解决一些实际问题,包括取消请求和页面卸载的关联,利用useEffect和AbortController等技术实现请求的取消。文章中的代码是简化后的例子,但思想是相通的。 ... [详细]
author-avatar
784485886_fe0643
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有