Dijkstra's algorithm for finding the shortest path in an undirected weighted graph - Java

Dijkstra's algorithm is a typical shortest path routing algorithm, which is used to calculate the shortest path from one node to all other nodes. The main feature is that it expands from the starting point to the outer layer until it reaches the end point.

The Dijkstra algorithm adopts the strategy of greedy algorithm. In the whole process of the algorithm, two tables have to be maintained. These two tables represent the nodes that have not been traversed and the nodes that have been traversed respectively. The approximate process is as follows:

  1. Declare two collections, open and close, open is used to store untraversed nodes, and close is used to store traversed nodes;
  2. In the initial stage, the initial node is put into close, and all other nodes are put into open;
  3. Take the initial node as the center to traverse outward layer by layer, get the child node closest to the specified node, put it into close, and recalculate the path until the close contains all the child nodes.

I implemented this algorithm in Intellij IDEA, same as BFS algorithm, first we need to build a graph to test. Here, I build the following diagram:

write picture description here
The following is the construction code. First, a Node object is created to encapsulate the vertex node information in the graph. It includes the node name and child nodes, and the child nodes are all adjacent nodes.

public class Node {
    private String name;
    private Map<Node,Integer> child=new HashMap<>();
    public Node(String name){
        this.name=name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Map<Node, Integer> getChild() {
        return child;
    }
    public void setChild(Map<Node, Integer> child) {
        this.child = child;
    }
}

Among them, constructor, getter and setter methods are automatically generated to facilitate node operations.

MapBuilder is used to initialize the data source and return the starting node of the graph.

public class MapBuilder {
    public Node build(Set<Node> open, Set<Node> close){
        Node nodeA=new Node("A");
        Node nodeB=new Node("B");
        Node nodeC=new Node("C");
        Node nodeD=new Node("D");
        Node nodeE=new Node("E");
        Node nodeF=new Node("F");
        Node nodeG=new Node("G");
        Node nodeH=new Node("H");
        nodeA.getChild().put(nodeB, 1);
        nodeA.getChild().put(nodeC, 1);
        nodeA.getChild().put(nodeD, 4);
        nodeA.getChild().put(nodeG, 5);
        nodeA.getChild().put(nodeF, 2);
        nodeB.getChild().put(nodeA, 1);
        nodeB.getChild().put(nodeF, 2);
        nodeB.getChild().put(nodeH, 4);
        nodeC.getChild().put(nodeA, 1);
        nodeC.getChild().put(nodeG, 3);
        nodeD.getChild().put(nodeA, 4);
        nodeD.getChild().put(nodeE, 1);
        nodeE.getChild().put(nodeD, 1);
        nodeE.getChild().put(nodeF, 1);
        nodeF.getChild().put(nodeE, 1);
        nodeF.getChild().put(nodeB, 2);
        nodeF.getChild().put(nodeA, 2);
        nodeG.getChild().put(nodeC, 3);
        nodeG.getChild().put(nodeA, 5);
        nodeG.getChild().put(nodeH, 1);
        nodeH.getChild().put(nodeB, 4);
        nodeH.getChild().put(nodeG, 1);
        open.add(nodeB);
        open.add(nodeC);
        open.add(nodeD);
        open.add(nodeE);
        open.add(nodeF);
        open.add(nodeG);
        open.add(nodeH);
        close.add(nodeA);
        return nodeA;
    }
}

Next comes the algorithm part, the Dijkstra class is used to calculate the shortest path from the starting node to all other nodes:

public class Dijkstra {
    Set<Node> open = new HashSet<Node>();
    Set<Node> close = new HashSet<Node>();
    Map<String, Integer> path = new HashMap<String, Integer>();//封装路径距离
    Map<String, String> pathInfo = new HashMap<String, String>();//封装路径信息

    public Node init() {
        //初始路径,因没有A->E这条路径,所以path(E)设置为Integer.MAX_VALUE
        path.put("B", 1);
        pathInfo.put("B", "A->B");
        path.put("C", 1);
        pathInfo.put("C", "A->C");
        path.put("D", 4);
        pathInfo.put("D", "A->D");
        path.put("E", Integer.MAX_VALUE);
        pathInfo.put("E", "A");
        path.put("F", 2);
        pathInfo.put("F", "A->F");
        path.put("G", 5);
        pathInfo.put("G", "A->G");
        path.put("H", Integer.MAX_VALUE);
        pathInfo.put("H", "A");
        //将初始节点放入close,其他节点放入open
        Node start = new MapBuilder().build(open, close);
        return start;
    }

    public void computePath(Node start) {
        //取距离start节点最近的子节点,放入close
        Node nearest = getShortestPath(start);
        if (nearest == null) {
            return;
        }
        close.add(nearest);     //已遍历的
        open.remove(nearest);   //未遍历的

        Map<Node, Integer> childs = nearest.getChild();
        for (Node child : childs.keySet()) {
            if (open.contains(child)) {//如果子节点在open中
                Integer newCompute = path.get(nearest.getName()) + childs.get(child);
                if (newCompute < path.get(child.getName())) {//新计算出来的距离小于之前设置的距离
                    path.put(child.getName(), newCompute);
                    pathInfo.put(child.getName(), pathInfo.get(nearest.getName()) + "->" + child.getName());
                }
            }
        }
        computePath(start);//重复执行自己,确保所有子节点被遍历
        computePath(nearest);//向外一层层递归,直至所有顶点被遍历
    }

    public void printPathInfo() {
        Set<Map.Entry<String, String>> pathInfos = pathInfo.entrySet();
        for (Map.Entry<String, String> pathInfo : pathInfos) {
            System.out.println(pathInfo.getKey() + ":" + pathInfo.getValue());
        }
    }

    /**
     * 获取与node最近的子节点
     */
    private Node getShortestPath(Node node) {
        Node res = null;
        int minDis = Integer.MAX_VALUE;
        Map<Node, Integer> childs = node.getChild();
        // 遍历与Node相连接的所有节点,选取其中距离最短的节点
        for (Node child : childs.keySet()) {
            if (open.contains(child)) {
                int distance = childs.get(child);
                if (distance < minDis) {
                    minDis = distance;
                    res = child;
                }
            }
        }
        return res;
    }
}

Then we built the test case as follows:

public class DijkstraTest { 
    /**
    *
    * Method: getShortestPath(Node node)
    *
    */
    @Test
    public void testGetShortestPath() throws Exception {
        //TODO: Test goes here...
        Dijkstra test=new Dijkstra();
        Node start=test.init();
        test.computePath(start);
        test.printPathInfo();
    }
} 

The results are as follows:

D:A->D
E:A->F->E
F:A->F
G:A->C->G
B:A->B
C:A->C
H:A->B->H

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324760950&siteId=291194637