[Java implementation] simple implementation of Nanjing Metro navigation system -- implementation of shortest path algorithm

        How to store information has been mentioned in the previous section. I won't repeat it here. Let's briefly review the implementation content. Since the newcomers don't know how long the blog can be sent, they still need to ask the viewer Tp to go to the previous section: [Java implementation] simple implementation of Nanjing Metro navigation system (I) -- storing station information_ kksp993 blog - CSDN blog
 

catalogue

Implementation content

problem analysis

Selection of algorithm

Design of weight vector table

         Floyd weight vector table

         Multi segment graph weight vector table

Algorithm design under three requirements (I) -- fewer sites

        Determination of weight vector table

Algorithm design under three requirements (II) -- replace with less

        Model modification

        Determination of weight vector table

Algorithm design under three requirements (III) -- less time

         Model modification

  Backtracking of path

  Backtracking for Floyd algorithm

  Backtracking for dynamic programming

Implementation content

        Take the operation diagram of Nanjing Metro as the template to realize the planning and dynamic display effect of the optimal path navigation between any two stations. Specific template pictures and requirements are as follows:

        1. Store the station information of Nanjing metro line.

        2. Given the starting station and terminal station, assuming that the path lengths of adjacent stations are equal, find the subway ride scheme with the shortest path;

        3. Given the starting station and terminal station, assuming that the path lengths of adjacent stations are equal, find the subway ride scheme with the least transfer times. If there are multiple ride schemes with the same transfer times, give the ride scheme with the least transfer times and the shortest path length.

        4. In practical application, the distance between adjacent stations is not equal. Assuming that the subway stay time in transfer station is T1, the subway stay time in non transfer station is T2, the time consumption of subway transfer is T3 (regardless of the time waiting for subway), the average subway speed is v, and the path length of adjacent stations is known. Try: given the starting station and terminal station, Seek the subway ride scheme with the shortest ride time.

        5. Design a visual query interface to dynamically display the above contents.

problem analysis

       Obviously, these five steps are based on the difficulty from shallow to deep, and can be divided into the following layers:

                (1) Minimum number of passing sites: the minimum number of passing sites can be realized by the number of passing sites from the beginning to the end

                 (2) Minimum transfer times: if it is changed to the minimum, it can be classified as a large penalty for the transfer at the above stations;

                 (3) Shortest theoretical time: it is necessary to calculate the waiting time, transfer time, operation time and many other factors respectively to correct the above process.

         This topic is progressive layer by layer, which obviously needs to use the method of transformation. Next, we will analyze the methods used.

Selection of algorithm

        The conventional algorithm selection is generally: dijestra algorithm and Freud algorithm.

                 Dijestra algorithm: [advantage] the complexity is lower than Floyd algorithm, which is O(e · logv).

                                             [disadvantage] because each query needs to go through every link of the algorithm again, and the response time is long.

                                 [related algorithm portal] Detailed principle, code implementation and complexity analysis of single source shortest path dijkstra algorithm_ Alan Zzx's blog - CSDN blog_ dijkstra algorithm complexity

                 Freudian algorithm:     [advantages] the routing matrix and routing overhead can be obtained at one time and saved for use. It does not need to be corrected until the map is updated.

                                              [disadvantage] the calculation time is too long:, and saving a large non sparse matrix undoubtedly increases the overhead.

                                [related algorithm portal] Shortest path template + parsing - (floyd algorithm)_ ytuyzh's blog - CSDN blog_ floyd algorithm

        These two methods are excellent methods that have been used for a long time, and we need to learn from them. However, the so-called reference is definitely not copying. We need to understand the essence, understand its core and use it thoughtfully. "Everything starts from reality and seeks truth from facts" is right. Do other people's pictures look the same as ours? Is it best if we use it directly? Not necessarily. Therefore, we should make a detailed analysis according to the specific situation, and we can't copy and do it with the aid of bookishness. In this way, there will be no progress. Seeing the essence of the problem is the best shortcut to help us solve the problem. If we rashly set up a formula without seeing the essence of the problem, it will only be a spectrum resistant drug, not a targeted specific drug. Although there is an effect, it is certainly not as good as a specific drug. This is the trade-off between scope and effect. You can't have both fish and bear's paw. Since the topic is specific, why not use "special drugs"?

        Without gossip, we can easily find that the subway route map has the following distinctive features:

                (1) The subway is mainly composed of a few transfer stations, accounting for almost 10%

                (2) Subway non transfer station can only travel in two directions, and it is only one-way for purposeful passengers. This means that the adjacency matrix is very sparse.

                (3) Subway is very careful about whether each line transfers or not, so the calculation of the shortest path generally needs special treatment.

        Therefore, we grasp the two characteristics of few transfer stations and no turning for non transfer, and we can think that the cost between non transfer can be regarded as a whole. In this way, there are less than 20 nodes that need to be concerned, and the rest are hidden in the weight information of the edge.

        Considering the above process combined with the meaning of the topic, Freud will no longer have a headache - the number of transfer stations is rare, the complexity is greatly reduced, and the time is greatly saved. Therefore, the whole problem is simplified as follows:

                (1) From the starting point to the transfer station

                (2) Transfer station Floyd arriving at the transfer station

                (3) From transfer station to terminal station

        Special treatment is required for those who do not need to transfer or only transfer once, because it may not be necessary to refer to the results of Floyd algorithm.

        Then we think, are these three steps very similar to the multi segment graph problem in the dynamic programming algorithm? Starting from the starting station is stage 0, the transfer station at the starting point is stage 1, the transfer station at the terminal is stage 2, and the terminal is stage 3. Since the step may be skipped if there is no transfer or less transfer, the unified process should not be omitted, but set the cost of the step to 0. The following figure shows the meaning of multi segment diagram and algorithm flow chart.

  [related algorithm portal]    Dynamic programming method to solve the shortest path problem of multi segment graph - Wuqi WhiteMoon - blog Park       

Design of weight vector table

        We need to provide two weight vector tables - Floyd weight vector table and multi segment graph weight vector table. Among the latterAndThe weight vectors between need to refer to the results of the former Floyd algorithm.

         Floyd weight vector table

        Because the algorithm records the weight vector between transfer stations, the node only includes less than 20 transfer stations; Because the graph is undirected, the weight vector matrix is a symmetric matrix. You only need to fill in the weight vector table in one direction and copy it according to the main diagonal. If there are m transfer stations, the matrix should be a symmetric matrix of m*m.

         Multi segment graph weight vector table

        Consider the composition of the weight vector table of the multi segment graph: it is not difficult to find that the main nodes are,,,. Let them form a row of vectors in orderThe array length of isThe length of the is, as shown in the figure below:

        In this way, the weight vector table labeled by the above row vector should be row and column A square of. Since this is a single source path calculation, only the shortest route in one direction needs to be answered, and the main diagonal elements are 0, so only the upper triangular matrix (excluding the main diagonal) is concerned. If the record "-" indicates no concern (set as INFTY), * indicates that there are numbers and INF indicates unreachable, so the following matrix can be initialized:

Algorithm design under three requirements (I) -- fewer sites

        Determination of weight vector table

         yesThe path weight should be the number of sides the path passes through, and forUnreachable binary pair, its path weight should be set to infinity:

Algorithm design under three requirements (II) -- replace with less

        Model modification

        Obviously, less transfer is the first goal, and less passing is the second goal. Those who have participated in the college entrance examination may have this experience. When the total score is the same, give priority to the calculation of math scores, English scores and Chinese scores (each province may be different, but ours is not the same set. Don't care about these details). How does the system calculate at this time? Those who have seen the final admission score understand that it will display 348.124139085 (I wrote it casually, don't take a seat according to the number). It seems that it just writes the results side by side. Why is there a distinction of priority? The reason is that it weights the score - equivalent to multiplying it by a weight vector.

        So, how to strengthen this goal and replace it with less in our model? As long as a penalty term (large coefficient) is set at the real transfer station, the results under the strengthened target will be given priority in the calculation process, and the influence of the non strengthened target will be limited. Specifically, Ts is set as the transfer station, Represents the edge on the OT path, and the objective function can be expressed as follows:

         among λ You should select a value that is much larger than the length of a single line. Select here λ= 100, of course, the bigger the better.

         (I conservatively chose 10 and then overturned...)

        Determination of weight vector table

         For the weight vector table, the penalty coefficient needs to be added in the following two aspects:

                (1) Floyd weight vector table: during initialization, each "*" needs to be added and replaced with a loss λ.

                (2) Multi segment graph weight vector table: for the first arrival at the transfer station and from the transfer station to the terminal station, it is necessary to increase and replace it with loss λ, Since the number of lines should be more than once, it can be considered to record onlyExchange loss λ. (if both are considered, it will be inconsistent with the actual situation, but it will have no impact on the program running results)

Algorithm design under three requirements (III) -- less time

         Model modification

       In practical application, the distance between adjacent stations is not equal. Many factors need to be considered, such as transit station subway dwell time, non transit station subway dwell time, subway running speed, subway running distance between each station and so on. According to the simplified model required by the topic, we set the transit station subway stay time as T1, the non transit station subway stay time as T2, the subway transfer time consumption as T3 (regardless of the waiting time for the subway), the average subway speed as v, and the path length of adjacent stations as d. Therefore, we need to recalculate the weight matrix under the new constraint.

         By consulting the data, we can get the information table of the distance between Nanjing Metro Stations: Distance between stations of Nanjing Metro Line S7 - Nanjing local treasure

Site index

1 / Mai Yao

2 / oil via

3 / forest forage

4 / Dragon Fairy

10 / rain an

s1 / Lu Nan

s3 / Huang Nan

s7 / none - Lu

s8 / Thai Kim

s9 / Xiang Gao

1

1142

2631

2537

1574

1729

7926

1712

1229

1236

10003

2

1121

1622

1049

1828

1154

4234

1998

2261

2741

7374

3

1691

1262

1127

821

1427

7283

1350

1529

2830

11219

4

1061

1379

1407

1359

1134

4723

1471

2423

1401

16912

5

1254

1473

1854

807

833

3242

1324

5236

1829

6232

6

862

1312

3535

1391

4545

3252

2099

3138

2151

0

7

1147

1257

961

2018

1350

4077

9844

5502

3880

0

8

1125

1002

1845

1128

1512

0

1525

5486

1567

0

9

909

874

1379

2749

848

0

2007

962

2893

0

10

1914

745

2017

2569

1865

0

1037

0

2077

0

11

2093

1022

2851

2564

1400

0

949

0

2375

0

12

1455

1024

858

3233

1307

0

1154

0

1606

0

13

1283

1300

859

1187

2157

0

1187

0

1475

0

14

1076

1521

931

1938

0

0

1608

0

6112

0

15

1853

1307

1067

2454

0

0

1446

0

4971

0

16

2276

937

1308

2185

0

0

1507

0

5475

0

17

1345

1168

1143

3212

0

0

1470

0

0

0

18

904

2779

977

0

0

0

1963

0

0

0

19

1332

3015

1153

0

0

0

0

0

0

0

20

1475

1675

1137

0

0

0

0

0

0

0

21

1135

1326

1222

0

0

0

0

0

0

0

22

1919

1519

1105

0

0

0

0

0

0

0

23

1312

1066

1826

0

0

0

0

0

0

0

24

1550

1947

1791

0

0

0

0

0

0

0

25

2720

1846

2343

0

0

0

0

0

0

0

26

1964

0

1526

0

0

0

0

0

0

0

27

0

0

1301

0

0

0

0

0

0

0

28

0

0

2995

0

0

0

0

0

0

0

         Since the current goal is to minimize the time consumption, the weights in the weight table should store the time consumption between two points. The time consumption of taking the subway can be divided into the following parts:

                 I.   Metro operation duration:

                 2. Subway stops and waits often:

                 3. Additional consumption of metro transfer station:

                 4. Additional consumption of transfer in Subway:

         In order to have the same function form as the first two questions and obtain a unified formula applicable to three types of problems for easy calling, the four functions are defined and unified as follows:

  Backtracking of path

  Backtracking for Floyd algorithm

         Generally, there are two modes for Floyd's routing matrix records on the Internet and in textbooks (more common...). One is the online version, which is forNot as good asThe grid update route array records K, and the other is written in algorithm design analysis and design (Chen Huinan). The recorded value here is path[k][j], that is, the last step before reaching j after passing through K. Let's compare the advantages and disadvantages of these two methods for this problem:

        (1) Record k: this path backtracking needs to be traversed in middle order in the form of binary tree. It may be difficult for those with poor knowledge of binary tree, and they need to constantly if...else.

        (2) Record the last routing path: this record form is linear, which is convenient to obtain the shortest path.

        Therefore, we choose the second way of recording, linear backtracking.

    /**
     * Find the transit path of S2 - > S3
     *
     * @return S2->S3 All transit paths, including arraylist at the beginning and end stations
     */
    private static ArrayList<Station> FloydTraceBack(Station s1, Station s2) {
//        if (s1.equals(s2)) System.err.println("FloydTraceBack-found:" + s1 + "==" + s2);
        ArrayList<Station> floydPath = new ArrayList<>();
        int idx1 = getStationIdx(TS_station, s1);
        Station temp = s2;
        do {
            floydPath.add(temp);
        } while (!s1.equals(temp = TS_path[idx1][getStationIdx(TS_station, temp)]));
        floydPath.add(s1);
        Collections.reverse(floydPath);
        return floydPath;
    }

  Backtracking for dynamic programming

        Because the backtracking in the first and third stages is the backtracking on the line, which is very simple; The intermediate backtracking has been completed in the above steps. Therefore, only these steps need to be connected in series. The details are as follows:

    /**
     * Find and add stations in turn to complete route planning
     * dp_path:[S0,S1,S2,S3]
     * TS-path:[all TS station]*[all TS station]
     * linear_path:Obtain the path array on the same line through the Station method
     *
     * @return path: Store all routing stations in S0, S1, S2 and S3 in turn
     */
    private static ArrayList<Station> trace4Path() {
        path.clear();
        //Record each station from back to front
        //S3
        Station s3 = dp_tags[dp_tags.length - 1];
        path.add(s3);
        //S3<-S2
        Station s2 = dp_path[dp_tags.length - 1];
        addList2Path(s3, s2);
        //S2 < - S1: obtain the route map of S1 - > S2, reverse the order and delete S2, and record the routing stations in turn
        Station s1 = dp_path[getStationLastIdx(dp_tags, s2)];
        if (s1.equals(s2))
        s1=dp_path[getStationIdx(dp_tags,s2)];
        //If only transfer is required, S1==S2 should skip S1 and directly S2 < - S0
        if (s1.isTS()) {
            ArrayList<Station> tbArrays = FloydTraceBack(s1, s2);
            Collections.reverse(tbArrays);
            tbArrays.remove(0);
            Station pre = s2;
            for (Station cur : tbArrays) {
                addList2Path(pre, cur);
                pre = cur;
            }
            //S1<-S0
            Station s0 = dp_path[0];
            addList2Path(s1, s0);
        } else {
            Station s0 = dp_path[0];
            addList2Path(s2, s0);
        }
        //Use Collections.reverse(path); In reverse order
        Collections.reverse(path);
        Utils.print1D(path.toArray(), 5, "path");
        return path;
    }

To sum up, the overall process is as follows:

        

    /**
     * Calculate and return the shortest distance between two stations
     *
     * @param S0 Starting station
     * @param S3 Terminus
     * @return distance
     */
    public static double PathNavigation(Station S0, Station S3, double TS_Non) {
        double d = A, d1 = A;
        double[][] Dp_w;
        System.out.println("------------start--------------" + TS_Non);
        //generate all station information
        if (!initStationInfo(S0, S3))
            d1 = getLinearDistance(S0, S3, TS_Non) - (TS_STAY_MIN - NON_STAY_MIN) * (TS_Non - 1);
        //generate all transferring stations' weight matrix
        TS_cost = initTS_W_Matrix(TS_Non);
        floyd();
        //generate dp's weight matrix
        Dp_w = initDp_W_Matrix(S0, S1, S2, S3, TS_Non);
        d = dp(Dp_w);
        //compare and the least cost between two methods
        if (d < d1)
            trace4Path();
        else
            System.out.println("Direct best:" + d1);
        System.out.println("-------------end---------------");
        return d;
    }

All codes in this file are listed below:

package core;

import utils.Utils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

/**
 * @author kksp993
 */
public class PathHelper {
    public static final int A = 2097152;
    public static final double TS_COST = 5;
    public static final double TS_STAY_MIN = 3;
    public static final double NON_STAY_MIN = 1;
    public static final double V_KM_H = 60;

    private static Station[] S1;
    private static Station[] S2;

    private static Station[] TS_station;
    private static double[][] TS_cost;
    private static Station[][] TS_path;

    private static Station[] dp_tags;
    private static double[] dp_cost;
    private static Station[] dp_path;

    private static ArrayList<Station> path;


    /**
     * Calculate and return the shortest distance between two stations
     *
     * @param S0 Starting station
     * @param S3 Terminus
     * @return distance
     */
    public static double PathNavigation(Station S0, Station S3, double TS_Non) {
        double d = A, d1 = A;
        double[][] Dp_w;
        System.out.println("------------start--------------" + TS_Non);
        //generate all station information
        if (!initStationInfo(S0, S3))
            d1 = getLinearDistance(S0, S3, TS_Non) - (TS_STAY_MIN - NON_STAY_MIN) * (TS_Non - 1);
        //generate all transferring stations' weight matrix
        TS_cost = initTS_W_Matrix(TS_Non);
        floyd();
        //generate dp's weight matrix
        Dp_w = initDp_W_Matrix(S0, S1, S2, S3, TS_Non);
        d = dp(Dp_w);
        //compare and the least cost between two methods
        if (d < d1)
            trace4Path();
        else
            System.out.println("Direct best:" + d1);
        System.out.println("-------------end---------------");
        return d;
    }

    /**
     * Initialize S0~S3 site information
     *
     * @param S0 Starting station
     * @param S3 Terminus
     * @return If directly connected, false, otherwise true
     */
    private static boolean initStationInfo(Station S0, Station S3) {
        path = new ArrayList<>();
        S1 = Utils.list2Array(S0.getLinearTs());
        S2 = Utils.list2Array(S3.getLinearTs());
        TS_station = Utils.list2Array(Station.getAllTS());
        if (S0.commonLineNum(S3) < A) {
            path.add(S0);
            addList2Path(S0, S3);
            return false;
        }
        return true;
    }

    /**
     * Obtain the shortest path by multi segment graph method:
     * 1)S0->S1:Process of non transfer station arriving at transfer station
     * ->stition Class to obtain the distance / station name of all transfer stations on your line
     * 2)S1->S2:The process of the transfer station arriving at the terminal transfer station
     * ->Floyd Get parameter table
     * 3)S2->S3:The process of CLP transit station reaching the key points
     * ->stition Class to obtain the distance / station name of all transfer stations on your line
     * The above parameters need to be passed in w
     *
     * @param w Record the matrix of all key nodes
     * @return Weight of the least path
     */
    public static double dp(double[][] w) {
        dp_cost = new double[w.length];
        dp_path = new Station[w.length];
        Arrays.fill(dp_cost, Integer.MAX_VALUE);
        dp_path[0] = dp_tags[0];
        dp_cost[0] = 0;
        for (int j = 1; j < w.length; j++)
            for (int i = j - 1; i >= 0; i--)
                if (w[i][j] != A) {
                    double d = dp_cost[i] + w[i][j];
                    if (d < dp_cost[j]) {
                        dp_cost[j] = d;
                        dp_path[j] = dp_tags[i];
                    }
                }
        Utils.print1D(dp_tags, 5, "dp_tags");
        Utils.print1D(dp_path, 5, "dp_path");
        Utils.print1D(dp_cost, 8, "dp_cost");
        return dp_cost[w.length - 1];
    }

    /**
     * floyd To calculate the weight variables between all transfer stations, TS needs to be prepared in advance_ cost
     */
    public static void floyd() {
        TS_path = new Station[TS_station.length][TS_station.length];
        //Initialize routing matrix
        for (int i = 0; i < TS_station.length; i++)
            for (int j = 0; j < TS_station.length; j++)
                TS_path[i][j] = TS_cost[i][j] < A ? TS_station[i] : null;
        //Traversal floyd
        for (int i = 0; i < TS_station.length; i++)
            for (int j = 0; j < TS_station.length; j++)
                for (int k = 0; k < TS_station.length; k++)
                    if (TS_cost[i][k] + TS_cost[k][j] < TS_cost[i][j]) {
                        TS_cost[i][j] = TS_cost[i][k] + TS_cost[k][j];
                        TS_path[i][j] = TS_path[k][j];
                    }
    }

    /**
     * Initialize the transfer station weight table for floyd algorithm
     *
     * @param TS_Non: The weight of transfer station and non transfer station is 10 by default. The weight of passing stations is 1 by default
     * @return
     */
    private static double[][] initTS_W_Matrix(double TS_Non) {

        double[][] w = new double[TS_station.length][TS_station.length];
        for (int i = 0; i < TS_station.length; i++) {
            Arrays.fill(w[i], A);
            for (int j = 0; j < TS_station.length; j++) {
                if (i == j) w[i][j] = 0;
                else
                    w[i][j] = getLinearDistance(TS_station[i], TS_station[j], TS_Non);
            }
        }
        return w;
    }

    /**
     * 1:Minimum station / 2: maximum speed / 100: minimum transfer
     *
     * @param s1     Starting station
     * @param s2     Terminus
     * @param TS_Non Transfer weight ratio = transfer station weight / non transfer station weight
     *               1:Minimum station / 2: maximum speed / 100: minimum transfer
     * @return S1 Linear shortest overhead to S2
     */
    private static double getLinearDistance(Station s1, Station s2, double TS_Non) {
        double speed = TS_Non == 2 ? V_KM_H / 60 * 1000 : 1;
        int isPd = TS_Non == 2 ? 1 : 0;
        //Generally, the station stops frequently
        double stayTime = Math.abs(s1.linearDistance(s2, false)) * NON_STAY_MIN;
        //Extra cost of transfer
        double TsExtraCost =  (TS_STAY_MIN - NON_STAY_MIN) * (TS_Non - 1);
        //Subway operation often
        double runningTime = isPd * Math.abs(s1.linearDistance(s2, true)) / speed;
        //Extra cost of routing transfer station
        double TsPassCost = isPd * s1.getInnerTsNum(s2) * (TS_COST - TS_STAY_MIN);
        return stayTime + TsExtraCost + runningTime + TsPassCost;
    }

    /**
     * Initialize weight table and header information
     *
     * @param S0      starting point
     * @param S1      Starting point transfer station
     * @param S2      Terminal transfer station
     * @param S3      End
     * @param TS_Non: The weight of transfer station and non transfer station is 10 by default. The weight of passing stations is 1 by default
     * @return Weight table
     */
    private static double[][] initDp_W_Matrix(Station S0, Station[] S1, Station[] S2, Station S3, double TS_Non) {
        double[][] w = new double[S1.length + S2.length + 2][S1.length + S2.length + 2];
        dp_tags = new Station[S1.length + S2.length + 2];
        //Initialize dp_tags is used to store header information:
        dp_tags[0] = S0;
        for (int i = 0; i < S1.length; i++) dp_tags[1 + i] = S1[i];
        for (int i = 0; i < S2.length; i++) dp_tags[1 + S1.length + i] = S2[i];
        dp_tags[dp_tags.length - 1] = S3;
        //w is initialized to infinity, indicating unreachable
        for (double[] w_row : w)
            Arrays.fill(w_row, A);
        //w diagonal all 0
        for (int i = 0; i < w.length; i++)
            w[i][i] = 0;
        //Process the weight table of S0 - > S1
        //The transfer ratio only calculates the starting point, not the ending point. TS has finished generating the Matrix
        for (int i = 0; i < S1.length; i++) {
            w[0][1 + i] = getLinearDistance(S0, S1[i], TS_Non);
        }
        //Process S1 - > S2 weight table
        for (int i = 0; i < S1.length; i++) {
            for (int j = 0; j < S2.length; j++) {
                int idx1 = getStationIdx(TS_station, S1[i]);
                int idx2 = getStationIdx(TS_station, S2[j]);
                //Only the upper triangle of w is processed
                w[1 + i][1 + S1.length + j] = TS_cost[idx1][idx2];
            }
        }
        //Process the weight table of S2 - > S3
        for (int i = 0; i < S2.length; i++) {
            //Remove the transfer ratio of multiple records at the tail end
            w[1 + S1.length + i][w.length - 1] = getLinearDistance(S3, S2[i], TS_Non) - (TS_Non - 1) * (TS_STAY_MIN - NON_STAY_MIN);
        }
        return w;
    }

    /**
     * Gets the coordinates of the station in the array
     *
     * @param stations Search scope
     * @param key      Looking for elements
     * @return index value found
     */
    private static int getStationIdx(Station[] stations, Station key) {
        for (int i = 0; i < stations.length; i++)
            if (key.equals(stations[i])) return i;
        return -1;
    }

    /**
     * Get the coordinates of the station in the array from back to front
     *
     * @param stations Search scope
     * @param key      Looking for elements
     * @return index value found
     */
    private static int getStationLastIdx(Station[] stations, Station key) {
        for (int i = stations.length - 1; i >= 0; i--)
            if (key.equals(stations[i])) return i;
        return -1;
    }

    /**
     * Find and add stations in turn to complete route planning
     * dp_path:[S0,S1,S2,S3]
     * TS-path:[all TS station]*[all TS station]
     * linear_path:Obtain the path array on the same line through the Station method
     *
     * @return path: Store all routing stations in S0, S1, S2 and S3 in turn
     */
    private static ArrayList<Station> trace4Path() {
        path.clear();
        //Record each station from back to front
        //S3
        Station s3 = dp_tags[dp_tags.length - 1];
        path.add(s3);
        //S3<-S2
        Station s2 = dp_path[dp_tags.length - 1];
        addList2Path(s3, s2);
        //S2 < - S1: obtain the route map of S1 - > S2, reverse the order and delete S2, and record the routing stations in turn
        Station s1 = dp_path[getStationLastIdx(dp_tags, s2)];
        if (s1.equals(s2))
        s1=dp_path[getStationIdx(dp_tags,s2)];
        //If only transfer is required, S1==S2 should skip S1 and directly S2 < - S0
        if (s1.isTS()) {
            ArrayList<Station> tbArrays = FloydTraceBack(s1, s2);
            Collections.reverse(tbArrays);
            tbArrays.remove(0);
            Station pre = s2;
            for (Station cur : tbArrays) {
                addList2Path(pre, cur);
                pre = cur;
            }
            //S1<-S0
            Station s0 = dp_path[0];
            addList2Path(s1, s0);
        } else {
            Station s0 = dp_path[0];
            addList2Path(s2, s0);
        }
        //Use Collections.reverse(path); In reverse order
        Collections.reverse(path);
        Utils.print1D(path.toArray(), 5, "path");
        return path;
    }

    /**
     * Add linear routing stations in turn to the arrival path, excluding the starting station
     *
     * @param sta Starting point site
     * @param end Terminal station
     * @return Current path
     */
    private static ArrayList<Station> addList2Path(Station sta, Station end) {
        Station[] stations = sta.linearPathTo(end);
//        if (stations==null) return path;
        for (int i = 1; i < stations.length; i++)
            path.add(stations[i]);
        return path;
    }

    /**
     * Find the transit path of S2 - > S3
     *
     * @return S2->S3 All transit paths, including arraylist at the beginning and end stations
     */
    private static ArrayList<Station> FloydTraceBack(Station s1, Station s2) {
//        if (s1.equals(s2)) System.err.println("FloydTraceBack-found:" + s1 + "==" + s2);
        ArrayList<Station> floydPath = new ArrayList<>();
        int idx1 = getStationIdx(TS_station, s1);
        Station temp = s2;
        do {
            floydPath.add(temp);
        } while (!s1.equals(temp = TS_path[idx1][getStationIdx(TS_station, temp)]));
        floydPath.add(s1);
        Collections.reverse(floydPath);
        return floydPath;
    }

    public static ArrayList<Station> getPath() {
        return path;
    }

}

         Well, the above is how to implement the shortest path algorithm to complete the data reading of three requirements. Thank you for three times with one click. In the next section, we will continue to talk about the production of simple GUI Graphical interface.

Tags: Java Programming Back-end

Posted on Wed, 17 Nov 2021 00:58:30 -0500 by eddie21leeds