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();
}
}
}
数据结构有向权重图:
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->