[Dijkstra]java-頂點爲String

import java.util.*;

/**
 * Dijkstras算法實現。
 *
 * Character改成String。
 * bug: 終點沒有定義時,空指針異常。解決方法:終點定義一個空的Vertex便可。
 * 不足:初始化Graph時,必須按節點來分組。(但初始化已分組好,效率更高)
 *
 * @author mburst
 * @author danni
 * @since 2019.7.16
 */
public class Dijkstras {
    static Graph g = null;

    private static void initGraph() {
        g = new Graph();
    }

    public static Graph getGraph() {
        return g;
    }

    public static void setGraph(String vertex, List<Vertex> vertexList) {
        if (g == null)
            initGraph();
        g.addVertex(vertex, vertexList);
    }

    public static List<String> getShortestPath(String src, String dest) {
        List<String> l = g.getShortestPath(src, dest);
        if (!l.isEmpty())
            l.add(src);
        Collections.reverse(l);// 倒序
        return l;
    }

}

@SuppressWarnings("Duplicates")
class Graph {

    private final Map<String, List<Vertex>> vertices;

    public Graph() {
        this.vertices = new HashMap<>();
    }

    public void addVertex(String str, List<Vertex> vertexList) {
        this.vertices.put(str, vertexList);
    }

    /**
     * 把頂點集合V分紅兩組:
     * (1)S:已求出的頂點的集合(初始時只含有源點V0)
     * (2)V-S=T:還沒有肯定的頂點集合
     *
     * 將T中頂點按遞增的次序加入到S中,保證:
     * (1)從源點V0到S中其餘各頂點的長度都不大於從V0到T中任何頂點的最短路徑長度
     * (2)每一個頂點對應一個距離值
     *
     * https://baike.baidu.com/item/迪傑斯特拉算法
     */
    public List<String> getShortestPath(String start, String finish) {

        final Map<String, Integer> distances = new HashMap<>();// 權重(距離)

        final Map<String, Vertex> previous = new HashMap<>();
        PriorityQueue<Vertex> nodes = new PriorityQueue<>();// 頂點的集合(初始時只含有源點V0的距離爲0,其他均爲inf)

        // 遍歷所有頂點集合,初始化距離,源點爲0,其餘爲正無窮(2147483647)
        for (String vertex : vertices.keySet()) {
            if (vertex == start) {// 源點
                distances.put(vertex, 0);
                nodes.add(new Vertex(vertex, 0));// 初始時只含有源點V0的距離爲0
            } else {// 非源點
                distances.put(vertex, Integer.MAX_VALUE);
                nodes.add(new Vertex(vertex, Integer.MAX_VALUE));// 其他均爲inf
            }
            previous.put(vertex, null);// 目前只有源點,所以前一個頂點先設置爲null
        }

        while (!nodes.isEmpty()) {
            // 最短距離的頂點
            Vertex smallest = nodes.poll();// 默認狀況下PriorityQueue使用天然排序法,最小元素先出列(offer入列,poll出列)

            // 若是最短距離的頂點爲目標頂點,則表示已求得最短路徑,直接返回
            if (smallest.getId() == finish) {
                final List<String> path = new ArrayList<>();
                // 循環把最短路徑的每個節點排列出來,放到path裏,而後返回path
                while (previous.get(smallest.getId()) != null) {
                    path.add(smallest.getId());
                    smallest = previous.get(smallest.getId());// 取前一個頂點
                }
                return path;
            }

            // 若是最短的距離是正無窮,則不用計算了,直接退出就能夠了(什麼時候這種狀況?)
            if (distances.get(smallest.getId()) == Integer.MAX_VALUE) {
                break;
            }

            for (Vertex neighbor : vertices.get(smallest.getId())) {
                // alt = 源點與當前(最短路徑)頂點的距離 + 當前頂點與它每個相鄰頂點的距離
                Integer alt = distances.get(smallest.getId()) + neighbor.getDistance();
//                System.out.println(neighbor.getId());
//                System.out.println(distances.get(neighbor.getId()));
//                System.out.println(alt);

                // 把alt與distances中保存的該頂點距離做比較,若是alt更小,則更新爲alt,讓distances始終保持裏面的距離是較小的,最終會最小
                if (alt < distances.get(neighbor.getId())) {// 若是沒定義終點,這裏distances.get會爲null,與alt比較會空指針異常
                    distances.put(neighbor.getId(), alt);
                    previous.put(neighbor.getId(), smallest);

                    // 更新該頂點在集合中的距離值
                    forloop:
                    for (Vertex n : nodes) {
                        if (n.getId() == neighbor.getId()) {
                            nodes.remove(n);// 先把頂點從集合作剔除
                            n.setDistance(alt);
                            nodes.add(n);// 再把該頂點加到集合,實際上是爲了修改該頂點的距離值
                            break forloop;
                        }
                    }
                }
            }
        }

        // 終點不存在的狀況(會break),會返回所有,bug
        //return new ArrayList<>(distances.keySet());

        // 修改成返回空
        return new ArrayList<>();
    }

}


@SuppressWarnings("Duplicates")
public class Vertex implements Comparable<Vertex> {

    private String id;
    private Integer distance;

    public Vertex(String id, Integer distance) {
        super();
        this.id = id;
        this.distance = distance;
    }

    public String getId() {
        return id;
    }

    public Integer getDistance() {
        return distance;
    }

    public void setId(String id) {
        this.id = id;
    }

    public void setDistance(Integer distance) {
        this.distance = distance;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((distance == null) ? 0 : distance.hashCode());
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Vertex other = (Vertex) obj;
        if (distance == null) {
            if (other.distance != null)
                return false;
        } else if (!distance.equals(other.distance))
            return false;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Vertex [id=" + id + ", distance=" + distance + "]";
    }

    @Override
    public int compareTo(Vertex o) {
        if (this.distance < o.distance)
            return -1;
        else if (this.distance > o.distance)
            return 1;
        else
            return this.getId().compareTo(o.getId());
    }

}


import java.util.Arrays;

public class Test {

    public static void main(String[] args) {
        initTest();
        System.out.println(Dijkstras.getShortestPath("A", "C"));
        System.out.println(Dijkstras.getShortestPath("A", "G"));
        System.out.println(Dijkstras.getShortestPath("A", "F"));
        System.out.println(Dijkstras.getShortestPath("A", "D"));
        System.out.println(Dijkstras.getShortestPath("A", "E"));// E並不存在
        System.out.println(Dijkstras.getShortestPath("A", "H"));// 沒法達到H
    }

    static void testMotor() {
        init();
        System.out.println(Dijkstras.getShortestPath("1234500100001000", "1234500100001410"));
        System.out.println(Dijkstras.getShortestPath("1234500100001410", "1234500100001000"));
    }

    private static void init() {
        Graph g = Dijkstras.g;
        g.addVertex("1234500100001000", Arrays.asList(new Vertex("1234500100001210", 0)));
        g.addVertex("1234500100001210", Arrays.asList(new Vertex("1234500100001200", 7400)));
        g.addVertex("1234500100001200", Arrays.asList(new Vertex("1234500100001410", 0)));
        g.addVertex("1234500100001410", Arrays.asList());
    }

    private static void initTest() {
        Graph g = Dijkstras.g;
        g.addVertex("A", Arrays.asList(new Vertex("B", 7), new Vertex("C", 8)));
        g.addVertex("B", Arrays.asList(new Vertex("C", 8), new Vertex("F", 2)));
        g.addVertex("C", Arrays.asList(new Vertex("F", 6), new Vertex("G", 4)));
        g.addVertex("D", Arrays.asList(new Vertex("F", 8)));
        g.addVertex("F", Arrays.asList(new Vertex("C", 6), new Vertex("G", 9), new Vertex("D", 8)));
        g.addVertex("G", Arrays.asList(new Vertex("C", 4), new Vertex("F", 9)));
        g.addVertex("H", Arrays.asList());
    }
}
相關文章
相關標籤/搜索