Dijkstra单源最短路径算法
此算法用于求出图中的一个源点到其余各点的最短路径,此图必须为带权图且不能有负权值,是否为有向图则没关系
算法思想关键:
设定一个源点s,遍历它的邻边,求出邻边中权值最小的那条边e,获得e另一端点v,则s到v的最短路径必定就是e,因为s到其他点的长度本来就长于e,若还从其他点折回v的话,那长度一定长于e(因此不能有负权边)。然后继续遍历v的邻边,若邻边中最短的边h的另一端点a是之前源点s(即v的上一级节点)遍历过的,则判断h的长度加上e的长度是否小于之前获得的s->a的长度,小于则更新a的相关数据,下面看代码:
类Dijkstra:
public class Dijkstra {
private SparseGraph sg; //有向图
private int s; //源点
private int[] distTo; //存储源点到各点的距离
private boolean[] marked;
private ArrayList<Edge> from=new ArrayList<Edge>(); //存储指向该顶点的边Edge
public Dijkstra(SparseGraph sg, int s) {
this.sg = sg;
this.s = s;
distTo=new int[sg.V()];
marked=new boolean[sg.V()];
for(int i=0;i<sg.V();i++){
distTo[i]=0;
marked[i]=false;
from.add(null);
}
IndexMinHeap imh=new IndexMinHeap(sg.V());
//Dijkstra
marked[s]=true;
imh.insert(s, distTo[s]);
while(!imh.isEmpty()){
int v=imh.extractMinIndex();
//distTo[v]就是s到v的最短距离
marked[v]=true;
ArrayList<Edge> arr=sg.getGraph(v);
Iterator<Edge> ite=arr.iterator();
while(ite.hasNext()){
Edge e=ite.next();
int w=e.other(v);
if(!marked[w]){ //w没有marked即表示s到w的最短路径没有找到
if(from.get(w)==null||distTo[v]+e.wt()<distTo[w]){ //from.get(w)==null表示e这条路径没访问过
distTo[w]=distTo[v]+e.wt(); //若 distTo[v]+e.wt()<distTo[w],则此操作为松弛操作
from.set(w, e); //若 distTo[v]+e.wt()<distTo[w],则此操作更新了s到w的最短路径的最后一段
if(imh.contain(w))
imh.set(w, distTo[w]);
else
imh.insert(w, distTo[w]);
}
}
}
}
}
//返回源点到w点的最短路径的权值和
public int shortestPathTo(int w){
return distTo[w];
}
//源点到w点是否有路径
public boolean hasPathTo(int w){
return marked[w];
}
private void shortestPath(int w,ArrayList<Edge> path){
Stack<Edge> s = new Stack<Edge>();
Edge e=from.get(w); //得到指向w点的路径
while(e!=null){
s.push(e);
e=from.get(e.v());
}
while(!s.isEmpty()){
e=s.peek();
path.add(e);
s.pop();
}
}
public void showPath(int w){
assert(w>=0&&w<sg.V());
ArrayList<Edge> path=new ArrayList<Edge>();
shortestPath(w,path);
for(int i=0;i<path.size();i++){
System.out.print(path.get(i).v()+"->");
if(i==path.size()-1){
System.out.print(path.get(i).w());
}
}
}
public static void main(String[] args) {
int N=10; //顶点
int M=60; //边
SparseGraph sg=new SparseGraph(N,true);
for(int i=0;i<M;i++){
sg.addEdge(new Random().nextInt(N), new Random().nextInt(N),new Random().nextInt(40)+1);
}
Dijkstra di=new Dijkstra(sg,3);
for(int i=0;i<sg.V();i++){
if(di.hasPathTo(i)){
di.showPath(i);
}
System.out.println();
}
}
}
结果如图: