
本教程详细讲解如何在java中实现一个航班路径可视化程序,重点解决如何根据用户提供的中转城市,准确显示该中转城市的所有直接连接及其到最终目的地的总距离。我们将通过优化图遍历逻辑和距离计算方法,确保程序能够正确地筛选并展示从起始城市经中转城市到达目的地的完整路径及累计里程。
引言:构建航班网络可视化系统
在航空领域,航班路径的可视化和距离计算是常见的需求。通过图数据结构,我们可以高效地表示城市(节点)和航班线路(边),并附加距离信息(边的权重)。本教程将指导您如何在一个已有的Java航班网络程序中,实现一个功能,即当用户指定一个中转城市后,程序能够准确地列出从该中转城市出发的所有直接连接,并计算从起始城市到这些最终目的地的总距离。
理解现有航班图结构
在深入解决问题之前,我们先回顾一下当前程序中使用的核心类和数据结构:
-
Vertex.java:
- 表示图中的一个节点(城市)以及从其“父节点”到自身的权重(距离)。
- label: 城市名称(字符串)。
- weight: 到达该城市的距离(整数)。
public class Vertex { String label; int weight; public Vertex(String label, int weight) { this.label = label; this.weight = weight; } } -
HWGraph.java:
立即学习“Java免费学习笔记(深入)”;
- 表示整个航班网络图,采用邻接表(Adjacency List)的形式存储。
- graphMap: HashMap
>,其中键是城市名称(字符串),值是该城市所有直接连接的Vertex对象列表。每个Vertex对象代表一个可达的城市及其与当前城市的距离。 - addVertex(String label): 添加一个城市到图中。
- addEdge(String label1, Vertex v): 添加一条从label1到v.label的边,距离为v.weight。
- getConnections(String label): 获取指定城市的所有直接连接。
- getThisVertex(String startCity, String destCity): 在startCity的连接中查找destCity对应的Vertex对象,用于获取从startCity到destCity的距离。
import java.util.ArrayList; import java.util.HashMap; import java.util.Set; public class HWGraph { public HashMap> graphMap = new HashMap<>(); public void addVertex( String label ){ ArrayList items = new ArrayList<>(); graphMap.put( label, items); } // ... (其他方法省略) ... ArrayList getConnections( String label){ return graphMap.get(label); } Vertex getThisVertex( String startCity, String destCity){ ArrayList destCities = this.getConnections( startCity); for( Vertex v : destCities){ if ( v.label.equalsIgnoreCase(destCity)){ return v; } } return null; } }
识别并解决核心问题
原始代码中的showConnections方法存在两个主要问题:
- 遍历范围不准确: showConnections方法通过g.graphMap.forEach((key, value) -> connect(key, value));遍历了整个图的所有连接,而不是仅仅显示用户指定中转城市的后续连接。
- 距离计算不完整: connect方法只打印了单段距离,没有将从起始城市到中转城市的距离考虑在内,以计算总距离。
为了解决这些问题,我们需要对HWDriverPrep.java中的showConnections方法及其调用逻辑进行重构。
优化连接显示逻辑
我们将修改showConnections方法,使其能够:
- 只关注特定中转城市的连接。
- 接收从起始城市到中转城市的累计距离。
- 计算并显示从起始城市经中转城市到最终目的地的总距离。
1. 重构 showConnections 方法
首先,我们将移除原showConnections中遍历整个graphMap的逻辑,并引入新的参数来传递中转城市的名称和从起始城市到中转城市的距离。
// HWDriverPrep.java
// ... (其他不变的代码) ...
private static void showConnections(HWGraph g, String layOverCityLabel, int distanceToLayover) {
// 1. 获取中转城市的所有直接连接
ArrayList connections = g.getConnections(layOverCityLabel);
// 2. 处理无后续连接的情况
if (connections == null || connections.isEmpty()) {
System.out.printf(" 城市 %s 无后续连接。\n", layOverCityLabel);
return;
}
// 3. 打印中转城市信息
System.out.printf(" 从 %s (起始到中转总距离: %d) 出发,后续连接如下:\n", layOverCityLabel, distanceToLayover);
// 4. 遍历并打印每个后续连接及其总距离
for (Vertex destination : connections) {
int totalDistance = distanceToLayover + destination.weight; // 计算总距离
System.out.printf(" -> 目的地: %s, 段距离: %d, 总距离: %d\n",
destination.label, destination.weight, totalDistance);
}
}
// 原有的 connect 方法不再需要,因为其功能已被整合到 showConnections 中
// private static void connect(String key, ArrayList value) { ... } 2. 更新 main 方法中的调用
在main方法中,我们需要确保在调用showConnections时,传入正确的参数:中转城市的名称和从起始城市到中转城市的距离。
// HWDriverPrep.java
import java.util.ArrayList;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
public class HWDriverPrep {
public static void main(String[] args) {
HWGraph g = createGraph();
// printGraph( g ); // 可选:如果不需要打印整个图的连接,可以注释掉
Set keys = g.getKeys();
String startCity = "Chicago"; // 示例起始城市
// 获取用户输入的中转城市
String layOver = getLayOverCity( keys, startCity);
// 获取从起始城市到中转城市的Vertex对象。
// 这个Vertex对象的label是中转城市名,weight是从startCity到layOver的距离。
Vertex layOverVertexFromStart = g.getThisVertex(startCity, layOver);
if (layOverVertexFromStart == null) {
System.out.println("\n错误:指定的中转城市不存在或无法从起始城市直接到达。");
return;
}
System.out.printf("\n 从起始城市:%s 到中转城市:%s 的距离为: %d\n",
startCity, layOverVertexFromStart.label, layOverVertexFromStart.weight);
System.out.printf(" 中转城市 %s 的后续连接及总距离:\n", layOverVertexFromStart.label);
// 调用修改后的 showConnections 方法,传入中转城市名称和从起始城市到中转城市的距离
showConnections(g, layOverVertexFromStart.label, layOverVertexFromStart.weight);
}
// ... (createGraph, printGraph, show, getLayOverCity 等其他方法不变) ...
// printGraph 方法可以保留,用于调试或显示整个图的结构
private static void printGraph(HWGraph g) {
g.graphMap.forEach(
(key,value) -> show(key,value));
}
private static void show(String key, ArrayList value) {
System.out.println("Showing connections for key: " + key + "--------");
for(Vertex v : value){
System.out.println("City: " + v.label + " Distance: " + v.weight);
}
}
private static String getLayOverCity(Set keys, String startCity) {
// ... (此方法保持不变) ...
String oStr = "";
String cm = "";
for(String item: keys)
{
oStr += cm + item;
cm = ", ";
}
System.out.printf("Select a layover City(%s): ",oStr); // 改进提示信息
Scanner s = new Scanner(System.in);
String retItem = s.nextLine();
return retItem;
}
// createGraph 方法保持不变
private static HWGraph createGraph() {
HWGraph g = new HWGraph();
g.addVertex("Chicago");
g.addVertex("Dallas");
g.addVertex("Atlanta");
g.addVertex("New York");
g.addVertex("Houston");
g.addVertex("Orlando");
// --- now add connections
g.addEdge("Chicago",new Vertex("Dallas",968));
g.addEdge("Chicago",new Vertex("Atlanta",718));
g.addEdge("Chicago",new Vertex("New York",790));
g.addEdge("Dallas",new Vertex("Houston",239));
g.addEdge("Dallas", new Vertex("Orlando",1120));
g.addEdge("Houston", new Vertex("Orlando",967));
g.addEdge("Atlanta", new Vertex("Dallas",781));
g.addEdge("Atlanta", new Vertex("New York",870));
g.addEdge("Atlanta", new Vertex("Orlando",438));
g.addEdge("New York", new Vertex("Houston",1647));
g.addEdge("New York", new Vertex("Orlando",1080));
return g;
}
} 示例运行与输出
假设起始城市为 Chicago,用户输入中转城市为 New York。
- getThisVertex("Chicago", "New York") 将返回一个 Vertex("New York", 790) 对象,表示从芝加哥到纽约的距离是790。
- showConnections 方法将被调用为 showConnections(g, "New York", 790)。
- showConnections 内部会调用 g.getConnections("New York"),这将返回 [Vertex("Houston", 1647), Vertex("Orlando", 1080)]。
- 程序将遍历这些连接并计算总距离:
- 对于 Houston: 总距离 = 790 (Chicago->NY) + 1647 (NY->Houston) = 2437。
- 对于 Orlando: 总距离 = 790 (Chicago->NY) + 1080 (NY->Orlando) = 1870。
最终输出将类似于:
Select a layover City(Chicago, Dallas, Atlanta, New York, Houston, Orlando): New York
从起始城市:Chicago 到中转城市:New York 的距离为: 790
中转城市 New York 的后续连接及总距离:
从 New York (起始到中转总距离: 790) 出发,后续连接如下:
-> 目的地: Houston, 段距离: 1647, 总距离: 2437
-> 目的地: Orlando, 段距离: 1080, 总距离: 1870注意事项与最佳实践
- 参数的有效利用: 确保每个方法参数都有其明确的用途。在原始代码中,showConnections的layOverVertex参数未被有效利用,导致逻辑错误。重构后,我们将其拆分为layOverCityLabel和distanceToLayover,使其职责更清晰。
- 职责单一原则: 每个方法应只负责一项明确的任务。getConnections负责获取特定节点的邻接列表,showConnections则负责格式化并显示这些连接及其总距离。避免一个方法承担过多不相关的职责。
- 错误处理: 在main方法中,我们增加了对layOverVertexFromStart == null的检查,以处理用户输入无效中转城市或该城市无法从起始城市直接到达的情况。
- 代码可读性: 使用有意义的变量名和清晰的输出格式可以大大提高代码的可读










