[data structure and algorithm] Chapter 19 and 20: weighted directed graph, shortest path (relaxation technology, Dijkstra algorithm)

19. Weighted directed graph

19.1 representation of edges

  • API

  • code
package chapter19;

/**
 * @author Soil flavor
 * Date 2021/9/17
 * @version 1.0
 * Directed edge
 */
public class DirectedEdge {
    /**
     * starting point
     */
    private final int v;
    /**
     * End
     */
    private final int w;
    /**
     * weight
     */
    private final double weight;

    /**
     * constructor 
     * @param v
     * @param w
     * @param weight
     */
    public DirectedEdge(int v, int w, double weight) {
        this.v = v;
        this.w = w;
        this.weight = weight;
    }

    /**
     * Get the starting point
     * @return
     */
    public int from(){
        return v;
    }

    /**
     * Get the end
     * @return
     */
    public int to(){
        return w;
    }

    /**
     * Get weight
     * @return
     */
    public double getWeight(){
        return weight;
    }
}

19.2 implementation of weighted directed graph

  • API

  • code
package chapter19;

import chapter03.Queue;
import chapter17.Edge;

/**
 * @author Soil flavor
 * Date 2021/9/16
 * @version 1.0
 * Weighted directed graph
 */
public class EdgeWeightedDigraph {
    /**
     * Number of vertices
     */
    private final int vNum;
    /**
     * Number of edges
     */
    private int eNum;
    /**
     * Adjacency table
     */
    private Queue<DirectedEdge>[] adj;

    /**
     * constructor 
     *
     * @param vNum
     */
    public EdgeWeightedDigraph(int vNum) {
        // Number of initialization vertices
        this.vNum = vNum;
        // Number of initialized edges
        this.eNum = 0;
        // Initialize adjacency table
        this.adj = new Queue[vNum];
        // Initializes an empty queue in the adjacency table
        for (int i = 0; i < vNum; i++) {
            this.adj[i] = new Queue<DirectedEdge>();
        }
    }

    /**
     * Get the number of vertices
     *
     * @return
     */
    public int getVNum() {
        return vNum;
    }

    /**
     * Get the number of edges
     *
     * @return
     */
    public int getENum() {
        return eNum;
    }

    /**
     * Add an edge v-w
     *
     * @param e
     */
    public void addEdge(DirectedEdge e) {
        // Because it is a directed graph, edges are added to the adjacency table of the starting point
        int v = e.from();
        this.adj[v].enQueue(e);

        // Number of edges plus 1
        eNum++;
    }

    /**
     * Gets all edges indicated by vertex v
     *
     * @param v
     * @return
     */
    public Queue<DirectedEdge> adj(int v) {
        return this.adj[v];
    }

    /**
     * Gets all edges in a weighted directed graph
     *
     * @return
     */
    public Queue<DirectedEdge> edges() {
        // Create a queue object to store all the edges
        Queue<DirectedEdge> allEdges = new Queue<>();

        // Traverse each vertex in the graph and find the adjacency table of each vertex. The adjacency table stores each edge pointed out by the vertex
        for (int v = 0; v < vNum; v++) {
            // Traverse the adjacency table of vertex v and find each edge pointed out by V
            for (DirectedEdge e : adj(v)) {
                allEdges.enQueue(e);
            }
        }

        return allEdges;
    }
}

20. Shortest path

20.1 definition and nature

  • definition

    In a weighted digraph, the path with the smallest total weight among all paths from vertex s to vertex t

  • nature

    • The path is directional

    • Weight is not necessarily equivalent to distance

      The weight can be distance, time, cost, etc. the smallest weight refers to the lowest cost

    • Only connected graphs are considered

      Not all vertices in a graph are reachable. If s and t are not reachable, there is no shortest path between them. In order to simplify the problem, only connected graphs are considered here

    • The shortest path is not necessarily unique

      There may be many paths with the least weight from one vertex to another. Here, just find one

  • Shortest path tree

    • Given a weighted directed graph and a vertex s, a shortest path tree starting from s is a subgraph of the graph, which contains vertex s and all vertices reachable from S. The root node of the directed tree is s, and each path of the tree is the shortest path in the directed graph

20.2. Shortest path tree API design

20.3 relaxation technology

The word relaxation comes from life: a rubber band is tightly spread along a path between two vertices. If there is more than one path between the two vertices and there is a shorter path, the rubber band can be relaxed by transferring the rubber band to a shorter path

The simple principle of relaxation can be used to calculate the shortest path tree

In the API, two member variables edgeTo and distTo are needed to store edges and weights respectively. At first, given a graph G and vertex s, you only know the edges of the graph and the weights of these edges, and you know nothing else. At this time, the total weight disto[s]=0 of the shortest path from vertex s to vertex s; The total weight from vertex s to other vertices is infinite by default. With the implementation of the algorithm, we continue to use relaxation technology to process the edges and vertices of the graph, and update the data in edgeTo and distTo according to certain conditions. Finally, we can get the shortest path tree

  • Edge relaxation

    Relaxing edge v - > W means checking whether the shortest path from s to w starts from s to v and then from v to w?

    If yes, v-w this edge needs to be added to the shortest path tree to update the contents in edgeTo and distTo:

    edgeTo[w] = DirectedEdge object representing V - > w this edge

    Distto [w] = distto [v] + V - > w this edge weight

    If not, the edge V - > W is ignored

  • Vertex relaxation

    The relaxation of vertices is based on the relaxation of edges. It is only necessary to relax all the edges pointed out by a vertex, and then the vertex is relaxed

    For example:

    To relax vertex v, just traverse the adjacency table of V and relax each edge, then vertex v is relaxed.
    If the starting point is set to vertex 0, the process of finding the shortest path 0 - > 2 - > 7 > 3 - > 6 from starting point 0 to vertex 6 is as follows:

20.4 implementation of Dijkstra algorithm

  • code
package chapter20;

import chapter03.Queue;
import chapter07.IndexMinPriorityQueue;
import chapter19.DirectedEdge;
import chapter19.EdgeWeightedDigraph;

/**
 * @author Soil flavor
 * Date 2021/9/18
 * @version 1.0
 * Dijestra shortest path algorithm
 */
public class DijkstraSP {
    /**
     * Last edge
     * The index represents the vertex
     * Value represents the last edge on the shortest path from vertex s to the current vertex
     */
    private DirectedEdge[] edgeTo;
    /**
     * Total weight
     * The index represents the total weight of the shortest path from vertex s to the current vertex
     */
    private double[] distTo;
    /**
     * Stores valid crosscutting edges between vertices in the tree and non vertices in the tree
     */
    private IndexMinPriorityQueue<Double> pq;

    /**
     * constructor 
     * According to a pair of weighted digraph G and vertex s, a shortest path tree object with vertex s is created
     * @param g
     * @param s
     */
    public DijkstraSP(EdgeWeightedDigraph g,int s) {
        // Initialize edgeTo
        this.edgeTo = new DirectedEdge[g.getVNum()];

        // Initialize distTo
        this.distTo = new double[g.getVNum()];
        for(int i = 0;i<g.getVNum();i++){
            // Default: positive infinity
            this.distTo[i] = Double.POSITIVE_INFINITY;
        }

        // Initialize pq
        this.pq = new IndexMinPriorityQueue<>(g.getVNum());

        // Find the shortest path tree starting from vertex s in graph g

        // By default, let vertices enter the shortest path tree
        this.distTo[s] = 0.0;
        this.pq.insert(s,0.0);

        // Traversal pq
        while(!this.pq.isEmpty()){
            relax(g,this.pq.delMin());
        }
    }

    /**
     * Vertex v in relaxation weighted digraph g
     * @param g
     * @param v
     */
    private void relax(EdgeWeightedDigraph g,int v){
        // Traversing adjacency table of vertex v
        for (DirectedEdge edge : g.adj(v)) {
            // Gets the end point of the edge w
            int w = edge.to();

            // Through relaxation technology: judge whether the shortest path from the starting point s to w should go through v: S - > v - > W
            if(distTo[v] + edge.getWeight() < distTo[w]){
                // Data needs to be updated through v:

                // Total weight of the shortest path from s to w
                distTo[w] = distTo[v] + edge.getWeight();
                // The last edge of the shortest path from s to w
                edgeTo[w] = edge;

                // Update pq
                if(pq.contains(w)){
                    pq.changeItem(w, edge.getWeight());
                }else{
                    pq.insert(w, edge.getWeight());
                }

            }
        }

    }

    /**
     * Gets the total weight of the shortest path from the starting point s to the vertex v
     * @param v
     * @return
     */
    public double distTo(int v){
        return distTo[v];
    }

    /**
     * Judge whether it is reachable from the starting point s to the vertex v
     * @param v
     * @return
     */
    public boolean hasPathTo(int v){
        // The default is positive infinity
        return distTo[v] < Double.POSITIVE_INFINITY;
    }

    /**
     * All edges of the shortest path from the starting point s to the vertex v
     * @param v
     * @return
     */
    public Queue<DirectedEdge> pathTo(int v){
        // If it is not reachable from the starting point s to v, null is returned
        if(!hasPathTo(v)){
            return null;
        }

        // Create a queue to receive the shortest path
        Queue<DirectedEdge> allEdges = new Queue<>();

        // Starting from v, use the last edge of edgeTo to push back to the starting point s and store it in the queue
        while (true){
            // Last edge of minimum path
            DirectedEdge e = edgeTo[v];
            // The last edge of the starting point is null, exit the loop
            if(e == null){
                break;
            }
            // Join queue
            allEdges.enQueue(e);

            // Update v and continue the cycle: because it is a directed edge, push back upward, and v is equal to the starting point of the edge
            v = e.from();
        }
        return allEdges;
    }
}
  • test
package chapter20;

import chapter03.Queue;
import chapter19.DirectedEdge;
import chapter19.EdgeWeightedDigraph;
import org.junit.Test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * @author Soil flavor
 * Date 2021/9/18
 * @version 1.0
 * Test weighted directed graph shortest path algorithm
 */
public class DijkstraSPTest {
    @Test
    public void test() throws IOException {
        // ---------Prepare a weighted directed graph----------
        BufferedReader br = new BufferedReader(new InputStreamReader(DijkstraSPTest.class.getClassLoader().getResourceAsStream("min_route_test.txt")));

        // Number of vertices
        int total = Integer.parseInt(br.readLine());
        // Weighted directed graph
        EdgeWeightedDigraph g = new EdgeWeightedDigraph(total);

        // Number of edges
        int edgeNum = Integer.parseInt(br.readLine());
        // Read edges in turn
        for (int i = 0; i < edgeNum; i++) {
            String[] s = br.readLine().split(" ");
            int v = Integer.parseInt(s[0]);
            int w = Integer.parseInt(s[1]);
            double weight = Double.parseDouble(s[2]);

            // Create weighted directed edges
            DirectedEdge edge = new DirectedEdge(v, w, weight);
            // Adding edges to a graph
            g.addEdge(edge);
        }

        // -----Create DijkstraSP object and find the shortest path tree-----
        DijkstraSP sp = new DijkstraSP(g, 0);

        // Find shortest path
        Queue<DirectedEdge> edges = sp.pathTo(6);

        // Print
        for (DirectedEdge e : edges) {
            int v = e.from();
            int w = e.to();
            double weight = e.getWeight();
            System.out.println(v + " - " + w + " : " + weight);
        }
    }
}
  • Test data: min_route_test.txt
8
15
4 5 0.35
5 4 0.35
4 7 0.37
5 7 0.28
7 5 0.28
5 1 0.32
0 4 0.38
0 2 0.26
7 3 0.39
1 3 0.29
2 7 0.34
6 2 0.40
3 6 0.52
6 0 0.58
6 4 0.93
  • Operation results
3 - 6 : 0.52
7 - 3 : 0.39
2 - 7 : 0.34
0 - 2 : 0.26

Tags: Algorithm data structure

Posted on Sat, 18 Sep 2021 14:25:49 -0400 by Shuriken1