热门标签 | 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;也是一次不可多得的实战经验呢^^



推荐阅读
  • 在Android应用开发中,实现与MySQL数据库的连接是一项重要的技术任务。本文详细介绍了Android连接MySQL数据库的操作流程和技术要点。首先,Android平台提供了SQLiteOpenHelper类作为数据库辅助工具,用于创建或打开数据库。开发者可以通过继承并扩展该类,实现对数据库的初始化和版本管理。此外,文章还探讨了使用第三方库如Retrofit或Volley进行网络请求,以及如何通过JSON格式交换数据,确保与MySQL服务器的高效通信。 ... [详细]
  • 本指南从零开始介绍Scala编程语言的基础知识,重点讲解了Scala解释器REPL(读取-求值-打印-循环)的使用方法。REPL是Scala开发中的重要工具,能够帮助初学者快速理解和实践Scala的基本语法和特性。通过详细的示例和练习,读者将能够熟练掌握Scala的基础概念和编程技巧。 ... [详细]
  • 在Android 4.4系统中,通过使用 `Intent` 对象并设置动作 `ACTION_GET_CONTENT` 或 `ACTION_OPEN_DOCUMENT`,可以从相册中选择图片并获取其路径。具体实现时,需要为 `Intent` 添加相应的类别,并处理返回的 Uri 以提取图片的文件路径。此方法适用于需要从用户相册中选择图片的应用场景,能够确保兼容性和用户体验。 ... [详细]
  • 在本地环境中部署了两个不同版本的 Flink 集群,分别为 1.9.1 和 1.9.2。近期在尝试启动 1.9.1 版本的 Flink 任务时,遇到了 TaskExecutor 启动失败的问题。尽管 TaskManager 日志显示正常,但任务仍无法成功启动。经过详细分析,发现该问题是由 Kafka 版本不兼容引起的。通过调整 Kafka 客户端配置并升级相关依赖,最终成功解决了这一故障。 ... [详细]
  • 本文介绍了如何利用ObjectMapper实现JSON与JavaBean之间的高效转换。ObjectMapper是Jackson库的核心组件,能够便捷地将Java对象序列化为JSON格式,并支持从JSON、XML以及文件等多种数据源反序列化为Java对象。此外,还探讨了在实际应用中如何优化转换性能,以提升系统整体效率。 ... [详细]
  • Java中不同类型的常量池(字符串常量池、Class常量池和运行时常量池)的对比与关联分析
    在研究Java虚拟机的过程中,笔者发现存在多种类型的常量池,包括字符串常量池、Class常量池和运行时常量池。通过查阅CSDN、博客园等相关资料,对这些常量池的特性、用途及其相互关系进行了详细探讨。本文将深入分析这三种常量池的差异与联系,帮助读者更好地理解Java虚拟机的内部机制。 ... [详细]
  • 深入解析 Android 中 EditText 的 getLayoutParams 方法及其代码应用实例 ... [详细]
  • 深入浅析JVM垃圾回收机制与收集器概述
    本文基于《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》的阅读心得进行整理,详细探讨了JVM的垃圾回收机制及其各类收集器的特点与应用场景。通过分析不同垃圾收集器的工作原理和性能表现,帮助读者深入了解JVM内存管理的核心技术,为优化Java应用程序提供实用指导。 ... [详细]
  • Squaretest:自动生成功能测试代码的高效插件
    本文将介绍一款名为Squaretest的高效插件,该工具能够自动生成功能测试代码。使用这款插件的主要原因是公司近期加强了代码质量的管控,对各项目进行了严格的单元测试评估。Squaretest不仅提高了测试代码的生成效率,还显著提升了代码的质量和可靠性。 ... [详细]
  • 尽管我们尽最大努力,任何软件开发过程中都难免会出现缺陷。为了更有效地提升对支持部门的协助与支撑,本文探讨了多种策略和最佳实践,旨在通过改进沟通、增强培训和支持流程来减少这些缺陷的影响,并提高整体服务质量和客户满意度。 ... [详细]
  • 手指触控|Android电容屏幕驱动调试指南
    手指触控|Android电容屏幕驱动调试指南 ... [详细]
  • 本文深入解析了Java 8并发编程中的`AtomicInteger`类,详细探讨了其源码实现和应用场景。`AtomicInteger`通过硬件级别的原子操作,确保了整型变量在多线程环境下的安全性和高效性,避免了传统加锁方式带来的性能开销。文章不仅剖析了`AtomicInteger`的内部机制,还结合实际案例展示了其在并发编程中的优势和使用技巧。 ... [详细]
  • 本文探讨了 Java 中 Pair 类的历史与现状。虽然 Java 标准库中没有内置的 Pair 类,但社区和第三方库提供了多种实现方式,如 Apache Commons 的 Pair 类和 JavaFX 的 javafx.util.Pair 类。这些实现为需要处理成对数据的开发者提供了便利。此外,文章还讨论了为何标准库未包含 Pair 类的原因,以及在现代 Java 开发中使用 Pair 类的最佳实践。 ... [详细]
  • SQLite数据库CRUD操作实例分析与应用
    本文通过分析和实例演示了SQLite数据库中的CRUD(创建、读取、更新和删除)操作,详细介绍了如何在Java环境中使用Person实体类进行数据库操作。文章首先阐述了SQLite数据库的基本概念及其在移动应用开发中的重要性,然后通过具体的代码示例,逐步展示了如何实现对Person实体类的增删改查功能。此外,还讨论了常见错误及其解决方法,为开发者提供了实用的参考和指导。 ... [详细]
  • 在Python中,是否可以通过使用Tkinter或ttk库创建一个具有自动换行功能的多行标签,并使其宽度能够随着父容器的变化而动态调整?例如,在调整NotePad窗口宽度时,实现类似记事本的自动换行效果。这种功能在设计需要显示长文本的对话框时非常有用,确保文本内容能够完整且美观地展示。 ... [详细]
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社区 版权所有