Dijkstra算法

2017-12-20 22:22:55

Dijkstra算法是用来计算单源最短路径(Single-Source Shortest Paths,SSSP)的一种常用算法,该算法要求所有的权值为非负值。即从单个源点出发,到所有结点的最短路。该算法同时适用于有向图和无向图。

输入:图的邻接矩阵或者是邻接表以及源点。

输出:源点到其他各个点的最短路径。

算法实现过程:Dijkstra算法维护了一组结点集合S,从源结点s到该集合中的每个点的最短路径已经被找到。算法重复从结点集V-S中选择最短路径估计最小的结点u,将u添加到S中,同时对u的所有边进行松弛操作。

清除所有点的标号

设d[s]=0,其他d[i]=INF

循环n次{

  在所有未标记结点中,选出d值最小的结点x

  给结点x标记

  对于从x出发的所有边(x,y),更新d[y] = min{d[y], d[x] + w(x,y)}

}

算法时间复杂度:

Java实现:

edges动态数组中保存的是边的详细信息,G中保存的只是边的编号。有了编号后再去edges中获得边的详细信息。其实就是邻接表的一种实现,这样在“遍历从x出发的所有边(x,y)更新d[y]”就可以写成“for(int i=0;i<G[u].size();i++) 执行每条边的松弛操作”。由于采用了邻接表的方式,所以使用聚合分析的时候松弛操作的执行次数是m次。这里使用的二叉堆的优先队列,每次更新都要花费logn,因此这里的消耗为mlogn。另外获取当前队首元素的时候也会消耗logn的维护时间,该项操作总共执行了n次,这里的消耗为nlogn。综上,总的时间消耗为(m+n)logn。

package dijkstra;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;

public class Dijkstra {
    int n;
    int m;
    final Integer maxn = 20;
    final int INF = 1 << 20;
    // 存放各个边的信息
    ArrayList<Edge> edges=new ArrayList<>();
    // 存放结点i的邻接边的存放下标
    ArrayList<Integer>[] G = new ArrayList[maxn];
    // 标记是否访问过
    boolean visited[] = new boolean[maxn];
    // s到各个点的距离
    int d[] = new int[maxn];
    // 最短路径的上一个结点
    int p[] = new int[maxn];

    void init(int n) {
        this.n = n;
        for (int i = 0; i < n; i++) {
            G[i] = new ArrayList<>();
        }
        edges.clear();
    }

    void addEdge(int from, int to, int dist) {
        edges.add(new Edge(from, to, dist));
        m = edges.size();
        G[from].add(m - 1);
    }

    void dijkstra(int s) {
        PriorityQueue<QueueNode> Q = new PriorityQueue<>(new Comparator<QueueNode>() {
            @Override
            public int compare(QueueNode o1, QueueNode o2) {
                return o1.d - o2.d;
            }
        });
        Arrays.fill(d, INF);
        d[s] = 0;
        Arrays.fill(visited, false);
        Arrays.fill(p, -1);
        Q.add(new QueueNode(0, s));
        while (!Q.isEmpty()) {
            QueueNode x = Q.poll();
            int u = x.u;
            if(visited[u]) continue;
            visited[u]=true;
            for (int i = 0; i < G[u].size(); i++) {
                Edge e = edges.get(G[u].get(i));
                if (d[e.to] > d[u] + e.dist) {
                    d[e.to] = d[u] + e.dist;
                    p[e.to]=u;
                    Q.add(new QueueNode(d[e.to], e.to));
                }
            }
        }
    }

    void printPath(int e) {
        if (p[e] != -1) {
            printPath(p[e]);
        }
        System.out.print(e+" ");
    }

    public static void main(String[] args) {
        Dijkstra dj=new Dijkstra();
        dj.init(5);
        dj.addEdge(0,1,10);
        dj.addEdge(0,3,30);
        dj.addEdge(0,4,100);
        dj.addEdge(1,2,50);
        dj.addEdge(2,4,10);
        dj.addEdge(3,2,20);
        dj.addEdge(3,4,60);
        dj.dijkstra(0);
        dj.printPath(2);
    }

}

class Edge {
    int from, to, dist;

    Edge(int u, int v, int d) {
        this.from = u;
        this.to = v;
        this.dist = d;
    }
}

class QueueNode {
    int d, u;

    QueueNode(int d, int u) {
        this.d = d;
        this.u = u;
    }
}
原文地址:https://www.cnblogs.com/hyserendipity/p/8076143.html