最短路径之Dijkstra算法的概念与实现

基本概念

要找出最短路径,其实就是从起点遍历所有能到达的顶点,然后计算他们的权重。Dijkstra算法核心在于边的松弛(relax),可以想象成一根绷紧的橡皮筋,让它放松下来。即是计算源点(s)经过当前点(v)到目标点(w)的权重,如果比目标点(w)之前的权重要小,就替换掉。最终的结果就是生成一颗最小路径树。这个算法和prim算法非常相似,甚至就是prim即时算法的变种。如果加权无向图和加权有向图的边和权重对应,最短路径树和最小生成树其实是等价的。
Dijkstra算法并不能处理权重为负数的边。

实现

distTo初始为无穷大意味着还没有访问过。如果顶点访问完后也是无穷大,就意味着不能到达。

/** * 迪杰斯塔拉算法 * @author yuli * */
public class Dijkstra implements Paths{
    private Edge[] edgeTo;//记录边的路径,从起始点到某个点,
    private double[] distTo;//到这个顶点的权重
    private int s;//开始的顶点
    private IndexMinPQ<Double> pq;//用来保存到最短路径树的最小边,也就是离最短路径树最近的边
    public Dijkstra(EdgeWeightedDiGraph graph,int s) {
        edgeTo = new Edge[graph.getV()];//初始化顶点路径
        distTo = new double[graph.getV()];//初始化到这个顶点的距离
        pq= new IndexMinPQ<>(graph.getV());
        this.s = s;
        //将起点到这个顶点的距离初始化为无穷大。
        for(int i = 0;i<graph.getV();i++){
            distTo[i] = Double.POSITIVE_INFINITY;
        }
        distTo[0]= 0.0d;
        pq.insert(s, 0.0);
        while(!pq.isEmpty()){
            relax(graph,pq.delMin());
        }

    }
    /** * 松弛边,松弛就是让权重变小 */
    private void relax(EdgeWeightedDiGraph graph,int v){
        Iterable<Edge> adj = graph.adj(v);

        for (Edge edge : adj) {
            int w = edge.to();//要松弛的目标顶点
            //如果目标顶点的权重大于当前顶点的权重+当前边的权重,就替换
            if(distTo[w] > distTo[v] + edge.getWeight()){
                distTo[w] = distTo[v] + edge.getWeight();
                edgeTo[w] = edge;//到这条边的最小权重
                //通过索引优先队列来减少比较次数
                if(pq.contains(w)){
                    pq.changeKey(w, distTo[w]);;
                }else{
                    pq.insert(w, distTo[w]);
                }
            }
        }
    }
    /** * 取得最短路径 * @param v * @return */
    public Iterable<Integer> pathTo(int v){
        if(hasPathTo(v)){
            throw new RuntimeException("没有此路径");
        }
        Stack<Integer> stack = new Stack<>();
        while(v != s){
            Edge e = edgeTo[v];
            stack.push(v);
            v = e.form();
        }
        stack.push(s);
        return stack;
    }
    /** * 获取最短路径的权重权重 * @return */
    public double weight(int v){
        return distTo[v];
    }
    public boolean hasPathTo(int v) {
        return distTo[v] == Double.POSITIVE_INFINITY;
    }
}
    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/yulio1234/article/details/77937528
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞