package org.loda.graph; import org.loda.structure.IndexMinQ; import org.loda.structure.Stack; import org.loda.util.In; /** * * @ClassName: Dijkstra * @Description: Dijkstra最短路徑算法--貪心算法 * @author minjun * @date 2015年5月27日 下午4:49:27 * */ public class Dijkstra { /** * 最短路徑上的前面一個節點 */ private int[] prev; /** * 距離遠點的距離 */ private double[] dist; /** * 利用帶索引的優先隊列來實現根據權重排序,以及根據索引i修改權重值 */ private IndexMinQ<Double> q; /** * 原點 */ private int s; /** * WeightDigraph g 加權有向圖 int s 起始點 */ public Dijkstra(WeightDigraph g, int s) { int v = g.v(); this.s=s; prev = new int[v]; dist = new double[v]; for (int i = 0; i < v; i++) { // 設默認前一個節點爲-1(這裏表示爲null) prev[i] = -1; // 設默認距離爲不可達 dist[i] = Integer.MAX_VALUE; } dist[s] = 0.0; q = new IndexMinQ<Double>(v); q.insert(s, dist[s]); while (!q.isEmpty()) { //利用貪心算法的思想,獲取當前距離遠點s最近的頂點,在這個頂點基礎之上擴展與其餘點的最近距離 int i = q.delMin(); //鬆弛這個頂點周圍全部的邊,直到s到達這些邊另外一端頂點的距離保持最小 relax(i, g); } } private void relax(int i, WeightDigraph g) { for (Edge edge : g.adj(i)) { int j = edge.otherSide(i); // i->j //若是s->j的距離比s->i+weigth(i->j)更近,那麼將s->j的距離dist和路徑prev修改成更近的距離和更優的前置點 if (dist[j] > dist[i] + edge.weight()) { dist[j] = dist[i] + edge.weight(); prev[j] = i; //找到當前最優解後更新或者添加這個較優解到優先隊列中 if (q.contains(j)) q.changeKey(j, dist[i]); else q.insert(j, dist[i]); } } } //原點->d的最短距離 public double distTo(int d){ return dist[d]; } //原點->d的最短路徑 public Iterable<Integer> pathTo(int i){ if(dist[i]==Integer.MAX_VALUE) throw new RuntimeException("沒法從原點"+s+"到達目標點"+i); Stack<Integer> reverse=new Stack<Integer>(); for(int v=i;v!=-1;v=prev[v]){ reverse.push(v); } return reverse; } public static void main(String[] args) { WeightDigraph g=new WeightDigraph(new In("F:\\算法\\attach\\tinyEWD.txt")); Dijkstra d=new Dijkstra(g, 0); for(int i=0;i<g.v();i++){ System.out.println("從原點"+d.s+"到"+i+"的最短距離爲:"+d.distTo(i)); System.out.print("路徑爲:"); for(int j:d.pathTo(i)){ System.out.print(j+"->"); } System.out.println(); } } }
數據結構有向權重圖: java
package org.loda.graph; import org.loda.structure.Bag; import org.loda.structure.Queue; import org.loda.util.In; /** * * @ClassName: WeightDigraph * @Description: 帶權重的有向圖 * @author minjun * @date 2015年5月27日 下午4:34:00 * */ public class WeightDigraph { private Bag<Edge>[] bags; private int v; private int e; private Queue<Edge> edges; @SuppressWarnings("unchecked") public WeightDigraph(int v) { this.v = v; bags = new Bag[v]; edges = new Queue<Edge>(); for (int i = 0; i < v; i++) { bags[i] = new Bag<Edge>(); } } public WeightDigraph(In in) { this(in.readInt()); int m = in.readInt(); for (int i = 0; i < m; i++) { add(in.readInt(), in.readInt(), in.readDouble()); } } public void add(int a, int b, double weight) { Edge edge = new Edge(a, b, weight); bags[a].add(edge); edges.enqueue(edge); e++; } public Iterable<Edge> adj(int a) { return bags[a]; } public Iterable<Edge> edges() { return edges; } public int v() { return v; } public int e() { return e; } }
8
15
4 5 0.35
5 4 0.35
4 7 0.37
5 7 0.28
7 5 0.28
5 1 0.32
0 4 0.38
0 2 0.26
7 3 0.39
1 3 0.29
2 7 0.34
6 2 0.40
3 6 0.52
6 0 0.58
6 4 0.93
算法
輸出結果: 數據結構
從原點0到0的最短距離爲:0.0 路徑爲:0-> 從原點0到1的最短距離爲:1.05 路徑爲:0->4->5->1-> 從原點0到2的最短距離爲:0.26 路徑爲:0->2-> 從原點0到3的最短距離爲:0.9900000000000001 路徑爲:0->2->7->3-> 從原點0到4的最短距離爲:0.38 路徑爲:0->4-> 從原點0到5的最短距離爲:0.73 路徑爲:0->4->5-> 從原點0到6的最短距離爲:1.5100000000000002 路徑爲:0->2->7->3->6-> 從原點0到7的最短距離爲:0.6000000000000001 路徑爲:0->2->7->