[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());
    }
}
相关文章
相关标签/搜索