算法導論——最短路徑Dijkstra算法

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->
相關文章
相關標籤/搜索