如果所采用的实现方式合适,Dijkstra算法的运行时间要低于前面所说的Bellman_Ford算法,但是Dijkstra算法要求图中没有负边。Dijkstra算法在运行过程中维持的关键信息是一组结点集合S。从源结点s到该集合中每个结点之间的最短路径已经被找到。算法重复从结点集V-S中选择最短路径估计最小的结点u,将u加入到集合S,然后对所有从u发出的边进行松弛(有关松弛操作可见http://blog.csdn.net/john_bian/article/details/74612722)。下面是《算法导论》书中所给的伪代码:
在这个实现方式中,我们使用了一个最小优先队列Q来保存结点集合,每个结点的关键值为其d值。下面则是运用Dijkstra算法求解单源最短路径的过程的一个例子。
以下是用Java代码的具体实现
package test7;
/**
* 边
* @author sdu20
*
*/
public class Edge {
private int v1;
private int v2;
private int weight;
public Edge(int v1,int v2,int weight){
this.v1 = v1;
this.v2 = v2;
this.weight = weight;
}
public boolean equals(Edge edge){
return this.v1==edge.getV1() && this.v2==edge.getV2() &&this.weight == edge.getWeight();
}
public int getV1(){
return v1;
}
public int getV2(){
return v2;
}
public int getWeight(){
return weight;
}
public String toString(){
String str = "[ "+v1+" , "+v2+" , "+weight+" ]";
return str;
}
}
package test7;
import java.util.*;
/**
* Dijkstra算法求解单源最短路径
* @author sdu20
*
*/
public class Graph {
private LinkedList<Edge>[] edgeLinks;
private int vNum; //顶点数
private int edgeNum; //边数
private int[] distance; //存放v.d
private int[] prenode; //存放前驱节点
private LinkedList<Integer> S; //已经求到最短路径的顶点集合
private LinkedList<Integer> Q; //尚未求到最短路径的顶点集合
public static final int INF = 10000; //无穷大
public static final int NIL = -1; //表示不存在
public Graph(int vnum){
this.vNum = vnum;
edgeLinks = new LinkedList[vnum];
edgeNum = 0;
distance = new int[vnum];
prenode = new int[vnum];
for(int i = 0;i<vnum;i++)
edgeLinks[i] = new LinkedList<>();
}
public void insertEdge(Edge edge){
int v1 = edge.getV1();
edgeLinks[v1].add(edge);
edgeNum++;
}
public void bianli(){
System.out.println("共有 "+vNum+" 个顶点, "+edgeNum+" 条边");
for(int i = 0;i<vNum;i++){
LinkedList<Edge> list = (LinkedList<Edge>) edgeLinks[i].clone();
while(!list.isEmpty()){
Edge edge = list.pop();
System.out.println(edge.toString());
}
}
}
/**
* 对最短路径估计和前驱节点进行初始化
* @param start
*/
public void INITIALIZE_SINGLE_SOURCE(int start){
for(int i = 0;i<vNum;i++){
distance[i] = INF;
prenode[i] = NIL;
}
distance[start] = 0;
}
/**
* 松弛
* @param edge
*/
public void RELAX(Edge edge){
int v1 = edge.getV1();
int v2 = edge.getV2();
int w = edge.getWeight();
if(distance[v2]>distance[v1]+w){
distance[v2] = distance[v1]+w;
prenode[v2] = v1;
}
}
/**
* Dijkstra算法实现
* @param start
*/
public void DIJKSTRA(int start){
INITIALIZE_SINGLE_SOURCE(start);
S = new LinkedList<>();
Q = new LinkedList<>();
for(int i = 0;i<vNum;i++){
Q.add(i);
}
while(!Q.isEmpty()){
int u = EXTRACT_MIN(Q);
S.add(u);
LinkedList<Edge> list = (LinkedList<Edge>) edgeLinks[u].clone();
while(!list.isEmpty()){
Edge edge = list.pop();
RELAX(edge);
}
}
ShowResult();
}
private int EXTRACT_MIN(LinkedList<Integer> q){
if(q.isEmpty())
return -1;
int min = q.getFirst();
for(int i = 0;i<q.size();i++){
int v = q.get(i);
if(distance[min]>distance[v]){
min = v;
}
}
int min2 = min;
q.remove(q.indexOf(min));
return min;
}
private void ShowResult(){
System.out.println("=========Result==========");
Stack<Integer>[] routes = new Stack[vNum];
for(int i = 0;i<vNum;i++){
routes[i] = new Stack<>();
int j = i;
while(j != NIL){
routes[i].push(j);
j = prenode[j];
}
System.out.print(i+"("+distance[i]+") : ");
while(!routes[i].isEmpty()){
int k = routes[i].pop();
System.out.print("-->"+k);
}
System.out.println();
}
}
}
package test7;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
bookGraph();
}
private static void bookGraph(){
Graph graph = new Graph(5);
Edge[] edges = new Edge[10];
edges[0] = new Edge(0,1,10);
edges[1] = new Edge(0,3,5);
edges[2] = new Edge(1,2,1);
edges[3] = new Edge(1,3,2);
edges[4] = new Edge(2,4,4);
edges[5] = new Edge(3,1,3);
edges[6] = new Edge(3,2,9);
edges[7] = new Edge(3,4,2);
edges[8] = new Edge(4,0,7);
edges[9] = new Edge(4,2,6);
for(int i = 0;i<10;i++)
graph.insertEdge(edges[i]);
graph.bianli();
graph.DIJKSTRA(0);
}
}
运行截图如下所示