地鐵線路最短路徑(程式碼實現)
阿新 • • 發佈:2020-11-05
提供一副地鐵線路圖,計算指定兩站之間最短(最少經過站數)乘車路線;
地鐵線路的資訊儲存在一份文字文件中,格式如下:
地鐵線路總數
線路名1 站名1 站名2 站名3 ...
線路名2 站名1 站名2 站名3 ...
線路名3 站名1 站名2 站名3 ......
主要功能
1:能夠讀取文字內容,並在使用者查詢時能夠正確顯示;
2:輸入起點和終點要求能夠輸出最短路徑站點總數;
3:輸出詳細的站點路線;
實現語言
Java
實現演算法
bfs演算法
類職責劃分
1、line類 :用於儲存路線名和該路線上的所有站點
public class line { private String LineName; //線名 private List<String> stations= new ArrayList<String>(); //該線路中所有站 //裡面的get set add省略未放上 }
2、station類 :用於儲存各個站點的具體資訊(名字、所在路線、與之相鄰的點等資訊)
private String StationName; //站點名 private List<String> Line = new ArrayList<String>(); //所線上路(換乘站有多條) private List<station> LinkStations= new ArrayList<station>(); //與之相鄰的站點 private boolean visited;//是否訪問過該站點 private String preStation;//本站之前訪問的站點 private int distance=0;//本站距離起點站的站數 private boolean change;//是否換乘 預設為false 用於結果 //裡面的get set add省略未放上
3、主函式中
public static HashMap<String,station> map = new HashMap<>();//方便查詢站點資訊
public static List<line> LineSet= new ArrayList<>();//方便查詢路線
核心程式碼
1、line類 :
private String LineName; //線名 private List<String> stations= new ArrayList<String>(); //該線路中所有站 public List<String> getStations() { return stations; } public void setStations(List<String> stations) { this.stations = stations; } public String getLineName() { return LineName; } public void setLineName(String lineName) { LineName = lineName; } public void stationAdd(String name){ stations.add(name); }
2、station類 :
private String StationName; //站點名
private List<String> Line = new ArrayList<String>(); //所線上路(換乘站有多條)
private List<station> LinkStations= new ArrayList<station>(); //與之相鄰的站點
private boolean visited;//是否訪問過該站點
private String preStation;//本站之前訪問的站點
private int distance=0;//本站距離起點站的站數
private boolean change;//是否換乘 預設為false 用於結果
public boolean ischange() {
return change;
}
public void setchange(boolean change) {
this.change = change;
}
public int getDistance() {
return distance;
}
public void setDistance(int distance) {
this.distance = distance;
}
public void AddStationLine(String name){
Line.add(name);
}
public void AddLinkStation(station sta){
LinkStations.add(sta);
}
public String getStationName() {
return StationName;
}
public void setStationName(String stationName) {
StationName = stationName;
}
public List<String> getLine() {
return Line;
}
public void setLine(List<String> line) {
Line = line;
}
public List<station> getLinkStations() {
return LinkStations;
}
public void setLinkStations(List<station> linkStations) {
LinkStations = linkStations;
}
public boolean isVisited() {
return visited;
}
public void setVisited(boolean visited) {
this.visited = visited;
}
public String getPreStation() {
return preStation;
}
public void setPreStation(String preStation) {
this.preStation = preStation;
}
3、主函式 :
主要分為三個方法
1)主要執行程式碼
public static void main(String[] ards){
read("D:\\homework\\軟體工程\\地鐵線路資訊.txt"); // 呼叫讀取檔案函式
Scanner scanner = new Scanner(System.in);
System.out.print("1:查詢該線路站點 2:查詢某站到某站的最短距離 請輸入操作序號:");
int chance = scanner.nextInt();
switch(chance) {
case 1:{
System.out.print("輸入想查詢的線路:");
String search = scanner.next();
for(line line2 : LineSet) {
if(line2.getLineName().equals(search)) {
for(int i = 1; i < line2.getStations().size(); i++ ) {
System.out.print(line2.getStations().get(i)+ " " );
}
}
}
break;
}
case 2:{
System.out.print("請輸入起點站:");
String start = scanner.next();
System.out.print("請輸入終點站:");
String end = scanner.next();
if (!map.containsKey(start)){//判斷起點站是否存在
System.out.println("起點站不存在");
break;
}
if (!map.containsKey(end)){//判斷終點站是否存在
System.out.println("終點站不存在");
break;
}
if (start.equals(end)){//判斷起點站和終點站是否相同
System.out.print("起點站與終點站相同 本站為" + end + "不需要乘坐地鐵");
break;
}
bfs(start,end);
PrintPath(start,end);
break;
}
default:{
System.out.println("請重新選擇");
break;
}
}
return;
}
2)read函式,用於讀取檔案地鐵資訊
public static void read(String name) {//讀入線路資料
try {
InputStreamReader reader = new InputStreamReader(new FileInputStream(name));
BufferedReader br = new BufferedReader(reader);
String read = null;
while((read = br.readLine()) != null) { //直到讀到空行位置
line line = new line();//當前存的line
String[] stations = read.split(" ");//讀入的line對應的所有station,並通過空格分割成字串陣列
line.setLineName(stations[0]);//修改其線路名
for (int j = 1; j < stations.length - 1; j++) {
station station1 = new station();//當前line中的station
station station2 = new station();
if (map.containsKey(stations[j])) {//如果map中已存在該站點
station1 = map.get(stations[j]);
map.remove(stations[j]);
} else { //否則創造一個站點,並初始化,用於開始階段
station1.setStationName(stations[j]);
station1.setVisited(false);
}
if (map.containsKey(stations[j + 1])) {//如果map中已存在該站點的後一站
station2 = map.get(stations[j + 1]);
map.remove(stations[j + 1]);
} else { //否則創造一個站點,並初始化,用於開始階段
station2.setStationName(stations[j + 1]);
station2.setVisited(false);
}
if (!station1.getLine().contains(line.getLineName()))//如果當前站未加入line中,則在line中當前站名
station1.AddStationLine(line.getLineName());
if (!station2.getLine().contains(line.getLineName()))//如果當前站未加入line中,則在line中當前站名
station2.AddStationLine(line.getLineName());
if (!station1.getLinkStations().contains(station2))
station1.AddLinkStation(station2);
if (!station2.getLinkStations().contains(station1))
station2.AddLinkStation(station1);
station1.setPreStation(station1.getStationName());
station2.setPreStation(station2.getStationName());
map.put(stations[j], station1);//把station1重新放回map
map.put(stations[j + 1], station2);//把station2重新放回map
if (!line.getStations().contains(station1.getStationName())) {
line.stationAdd(station1.getStationName());
}
if (!line.getStations().contains(station2.getStationName())) {
line.stationAdd(station2.getStationName());
}
}
LineSet.add(line);//把線路加入總的LineSet中,用於輸出
}
br.close();
}catch(Exception e){
e.printStackTrace();
}
}
3)bfs的實現函式
public static void bfs(String start, String end){
for (String a :map.keySet()){ //將每個節點進行初始化操作
map.get(a).setVisited(false);
map.get(a).setDistance(0);
}
station now = new station();
Queue<String> queue = new LinkedList<>();//使用佇列,實現bfs演算法
now = map.get(start);
queue.add(start);
while(!queue.isEmpty()){
String nowName = queue.remove();
map.get(nowName).setVisited(true);
if (now.getStationName().equals(end)){
break;
}
for (station station1 :map.get(nowName).getLinkStations()){
if(!map.get(station1.getStationName()).isVisited()){//未訪問過的臨近站點
map.get(station1.getStationName()).setPreStation(nowName);//為preStation賦值
map.get(station1.getStationName()).setDistance(map.get(nowName).getDistance()+1);//臨近站的距離為本站距離加1
queue.offer(station1.getStationName());
}
}
}
}
4)輸出路線和判斷換乘函式
public static void PrintPath(String start,String end){
List<String> path = new ArrayList<>();
Stack<String> printline = new Stack<>();
int num = 1;//第幾站
int cnt = 0;//換乘次數
String str = end;
while(!str.equals(start)){
path.add(str);
printline.push(str);
str = map.get(str).getPreStation();
}
path.add(str);//把start放入path
printline.push(str);
for (int i=1;i<path.size()-1;i++){
if (map.get(path.get(i)).getLine().size() == 1){
continue;
}
String temp1 = null;
String temp2 = null;
//每三戰判斷一次是否有換乘站
for (String str1 : map.get(path.get(i)).getLine()){//本站與前一站的共同擁有的線路存在temp1中
boolean flag = false;
for (String str2 :map.get(path.get(i-1)).getLine()){
if (str1.equals(str2)){
temp1 = temp1 + str1;
flag = !flag;
break;
}
}
if (flag) break;
}
for (String str1 : map.get(path.get(i)).getLine()){//後一站與本站的共同擁有的線路存在temp2中
boolean flag = false;
for (String str2 :map.get(path.get(i+1)).getLine()){
if (str1.equals(str2)){
temp2 = temp2 + str1;
flag = !flag;
break;
}
}
if (flag) break;
}
if (!temp1.equals(temp2))//若temp1和temp2兩線路不同則本站為轉乘站
map.get(path.get(i)).setchange(true);
}//判斷path中的換乘站
System.out.println("共"+path.size()+"站");
while(!printline.empty()){
String printStation = printline.pop();
if(num == 1){
for (String strnow : map.get(printStation).getLine()){
for (String nextStation : map.get(path.get(path.size()-num-1)).getLine()){
if (strnow.equals(nextStation)) {
System.out.println("當前線為:"+strnow);
}
}
}
}
if (map.get(printStation).ischange()){
String nowline ="";
for (String strnow : map.get(printStation).getLine()){
//path.get(path.size()-numStation)為換乘站下一站 兩站共有的線就是換乘線
for (String nextStation : map.get(path.get(path.size()-num-1)).getLine()){
if (strnow.equals(nextStation))
nowline = nowline + strnow;
}
}
cnt++;
System.out.println("");
System.out.println("轉線為" + nowline);
}
System.out.print(printStation + " ");
num++;
}
}
測試用例
查詢1號線線路時:
查詢最短路線時候
1、兩線存在一條線上時
2、兩線不存在一條線上時
查詢終點站不存在時
總結
此次實驗讓我發現我的程式設計能力非常的薄弱,日後有待提高;
這次是一一次寫部落格,有了一點點經驗,對日後一定有所幫助;
全部程式碼上交到https://github.com/chenyh1234/subway.git